如何使用LINQ选择器设置通用属性

时间:2012-06-15 15:49:17

标签: c# linq entity-framework linq-to-sql expression

我有多个查询,如下所示:

var query = from a in EntityAs
            select new EntityASmall()
            {
                // Common Stuff:
                Id = a.Id,
                Name = a.Name,
                ShortName = a.ShortName,
                // Specific to EntityA:
                ASpecificProperty1 = a.1,
                ASpecificProperty2 = a.2
            };

var query = from b in EntityBs
            select new EntityBSmall()
            {
                // Common Stuff:
                Id = b.Id,
                Name = b.Name,
                ShortName = b.ShortName,
                // Specific to EntityB:
                BSpecificProperty1 = b.1,
                BSpecificProperty2 = b.2
            };

EntityA和EntityB都派生自具有IdNameShortName属性的公共基类。 EntityASmallEntityBSmall也是如此。我有很多看起来像这样的查询,所以我想做一些简单的查询,首先得到常见的东西。我找到了一个看起来很有希望的扩展方法:

public static TSource SetCommonProperties<TSource>(this TSource input, EntityBaseClass entity, Action<TSource> updater) where TSource : EntitySmallBase
{
    input.Id = entity.Id;
    input.Name = entity.Name;
    input.ShortName = entity.Name;

    updater(input);

    return input;
}

我可以像这样使用它:

var query = from a in EntityAs.AsEnumerable()
            select new EntityASmall().SetCommonProperties(a, x =>
            {
                ASpecificProperty1 = x.1;
                ASpecificProperty2 = x.2;
            });

请注意AsEnumerable()。没有它,我得到“一个带有语句体的lambda表达式无法转换为表达式树”,我猜这粗略意味着它试图将Action部分转换为LINQ-to-SQL的表达式。看起来AsEnumerable()将集合放在本地完整的位置。对于冗长的帖子感到抱歉,但有没有任何表达方式来编写这个可以与LINQ-to-SQL和Entity Framework一起使用的方法?提前谢谢。

2 个答案:

答案 0 :(得分:1)

你想让你的代码DRY,这总是很好的努力。也许你会让你的方法与一些辛劳和劳动以及一些Expression伏都教,但也许你会去喜欢这个链接:Stop using AutoMapper in your Data Access Code。 (即使您不使用AutoMapper)。

通过这项精彩的工作,您将能够编写简洁的陈述,如:

context.EntityAs.Project().To<EntityASmall>();
context.EntityBs.Project().To<EntityBSmall>();

我自己也用过它,我非常喜欢它。

答案 1 :(得分:0)

您提出的扩展方法看起来不错。

它只是你必须为每个派生实体创建它,并且在你的情况下可能没问题,因为你似乎有几个衍生实体。

其次,我不认为你真的需要在你的扩展方法中传递那个动作委托。 相反,如果可能的话,只在那里调用该方法。我对设计不太了解。

所以你的扩展方法看起来像这样

public static TSource SetCommonProperties<TSource>(this TSource input, EntityBaseClass entity)     where TSource : EntitySmallBase 
{ 
   input.Id = entity.Id; 
   input.Name = entity.Name; 
   input.ShortName = entity.Name; 

   this.Update(input); // Or this method could exist in any other class or static class.

  return input; 

}

然后您也可以使用extesion方法。

var query = from a in EntityAs
        select new EntityASmall
        {      
            ASpecificProperty1      
            ASpecificProperty2    
        }).SetCommonProperties(a,entity)    

这将消除您使用AsEnumerable的用法。 如果你想要的话,你也可以用同样的方法从你的基础变换到derviced方法:

DerivceEntityObject SetCommonProperties(BaseEntity)

我希望这能让你了解我在这里建议的内容。