S1r-Lanzelot
S1r-Lanzelot

Reputation: 2266

How to handle different entities with same structure - linq queries essentially the same

I have two different entities (database first) that have the exact same structure but different naming conventions. Is there a way I can simplify the seemingly duplicated code that comes from querying them (ie in DoWorkWithSimilar)?

I have tried doing something with generics but am having troubles getting the linq queries to work. Also I try to shy away from generics when possible because I like to be more explicit. Nevertheless, the DoWorkWithSimilar methods in the two respective classes are extremely similar. I am trying to think of a better way to streamline these two classes (DoWorkSimilarOne and DoWorkSimilarTwo) however, due to my constraint on the structure of the underlying classes... I am struggling. Is there no better way?

 public class DoWorkSimilarOne : IDoWork
    {
        public IUnitOfWork unitOfWork;
        public DoWorkSimilarOne(IUnitOfWork _unitOfWork)
        {
           unitOfWork = _unitOfWork;
        }
        public IEnumerable<int> DoWorkWithSimilar(IEnumerable<int> otherIds)
        {

            IEnumerable<int> similarOneIds = unitOfWork.OtherSimilarOnes
                .Where(x => otherIds.Contains(x.Other.OtherId))
                .SelectMany(x => x.SimilarOnes)
                .Select(x => x.SimilarOneId).ToList();
            return similarOneIds;
        }

    }

    public class DoWorkSimilarTwo : IDoWork
    {
        public IUnitOfWork unitOfWork;
        public DoWorkSimilarTwo(IUnitOfWork _unitOfWork)
        {
           unitOfWork = _unitOfWork;
        }

        public IEnumerable<int> DoWorkWithSimilar(IEnumerable<int> otherIds)
        {

            IEnumerable<int> similarTwoIds = unitOfWork.OtherSimilarTwos
                .Where(x => otherIds.Contains(x.Other.OtherId))
                .SelectMany(x => x.SimilarTwos)
                .Select(x => x.SimilarTwoId).ToList();
            return similarTwoIds;
        }

    }

    public class SimilarOne
    {
        public int SimilarOneId { get; set; }
        public OtherSimilarOnes OtherSimilarOne { get; set; }
    }

    public class SimilarTwo
    {
        public int SimilarTwoId { get; set; }
        public OtherSimilarTwos OtherSimilarTwo { get; set; }
    }

    public class Other
    {
        public int OtherId { get; set; }
    }

    public class OtherSimilarOnes
    {
        public int Id { get; set; }
        public Other Other { get; set; }
        public IEnumerable<SimilarOne> SimilarOnes { get; set; }
    }

    public class OtherSimilarTwos
    {
        public int Id { get; set; }
        public Other Other { get; set; }
        public IEnumerable<SimilarTwo> SimilarTwos { get; set; }
    }

    public interface IDoWork
    {
        IEnumerable<int> DoWorkWithSimilar(IEnumerable<int> otherIds);
    }

Upvotes: 0

Views: 108

Answers (1)

Woody1193
Woody1193

Reputation: 7970

Seems to me that you just need to make your method generic and add some base classes, right?

public abstract class ObjectWithId
{
    public int Id { get; set; }
}

public class ObjectThatRelates<T> : ObjectWithId
    where T : ObjectWithId
{
    public int OtherId { get; set; }
    public IEnumerable<T> Similar { get; set; }
}

public class Object1 : ObjectWithId
{
    public ObjectThatRelates<Object1> { get; set; }
}

public class Object2 : ObjectWithId
{
    public ObjectThatRelates<Object2> { get; set; }
}

Then your methods become:

public IEnumerable<int> DoWorkWithSimilar<T>(IEnumerable<int> otherIds)
{
    IEnumerable<int> similarOneIds = unitOfWork.ObjectThatRelates<T>
        .Where(x => otherIds.Contains(x.OtherId))
        .SelectMany(x => x.Similar)
        .Select(x => x.Id).ToList();
     return similarOneIds;
}

Of course, your definition of IUnitOfWork will have to change so that it can return either ObjectThatRelates<Object1> or ObjectThatRelates<Object2> but this should allow you to avoid duplication of effort.

Upvotes: 1

Related Questions