【问题标题】:Linq to SQL, concatenate fields without new dynamic type creationLinq to SQL,连接字段而不创建新的动态类型
【发布时间】:2016-09-15 12:34:28
【问题描述】:

我想将字段连接成一个非字段,它是同一模型的属性。

我有一个 Person 的模型,其中包括一个名为 FullName 的非字段属性 (NotMapped):

public class Person
{
   public int Id{get;set;}
   public string firstname{get;set;}
   public string lastname{get;set;}

   [NotMapped]
   public string FullName{get;set;}
}

现在我想选择所有人及其FullName

FullName = string.format("{0} {1}",firstname, lastname);

我不想在列出表格后为每个人分配全名,因为性能和速度都不好(大约 10K 记录)

我不想使用如下的新选择(动态类型)

var list = from pf in db.Persons 
           select new 
                  {
                     Person = pf,
                     FullName = string.format("{0} {1}", pf.firstname, pf.lastname)
                  }
List<Person> persons = new List<Person>();

// bad performance
foreach(var item in list)
{
    item.Person.FullName = item.FullName;
    persons.Add(item);
}

除非你为它提供一个动态 lambda 函数,它具有通用模型类型和连接字段公式的表达式。

例如:

public List<TModel> GetList<TModel>(Expression<Func<TModel, string>> cField = null,...)
{
//all should done in database side with one query
//select all records include FullName
}

我不想使用 FullName.get

public string FullName
{
     get { return string.format("{0} {1}", pf.firstname, pf.lastname); }
} 

因为它与 foreach 方法相同,并且在 datagridview 中使用该类时性能较差。

换句话说,我需要的是一个选择所有人及其全名的 linq 查询。

请注意,数据库选择后的任何分配(特别是与接口一起使用时)的性能都很差。

【问题讨论】:

  • 你不能直接用public string FullName { get { return string.format("{0} {1}",firstname, lastname); } }吗?
  • 不!因为 fullname 是一个示例,而我需要的是超过 5 个字段的连接,所以处理 FullName.get 将花费宝贵的时间。它将绑定到 datagridview

标签: c# linq lambda linq-to-sql


【解决方案1】:

改变你的模型:

public class Person
{
 public int Id{get;set;}
 public string firstname{get;set;}
 public string lastname{get;set;}

 [NotMapped]
 public string FullName => firstname + " " + lastname;
}

【讨论】:

    【解决方案2】:

    只需使用一些 Dto 就可以了

    public class PersonDto
    {
     public int Id{get;set;}
     public string FirstName{get;set;}
     public string LastName{get;set;}
     public string FullName{get;set;}
    }
    

    然后像这样选择它

    db.Persons.Select(p => new PresonDto
                               {
                                   Id = p.Id,
                                   FirstName = p.firstname,
                                   LastName = p.lastname,
                                   FullName = p.firstname ?? "" + " " + p.lastname ?? ""
                               });
    

    编辑

    如果您不想使用 dtos 并且想要或多或少的通用方法,我看不到在 sql 查询期间填充对象属性的任何方法。并选择一些模型到 new Model() 并重新分配所有字段不是一个好主意。

    所以我能提供的唯一方法是使用一些容器来存储您的原始模型和您想要选择的其他字段。

    public class ItemAdditionalPropertyContainer<TModel>
    {
        public TModel Item { get; set; }
        public string PropertyValue { get; set; }
    }
    
    public static IQueryable<ItemAdditionalPropertyContainer<TModel>> GetItemsWithAdditionalProperty<TModel>(
        IQueryable<TModel> items,
        Expression<Func<TModel, string>> additionalPropertySelector)
    {
        Expression<Func<TModel, ItemAdditionalPropertyContainer<TModel>>> expr = 
            item => new ItemAdditionalPropertyContainer<TModel> 
                { 
                    Item = item, 
                    PropertyValue = additionalPropertySelector.Compile()(item)
                };
        return items.Select(expr.ExpandExpressions() );
    }
    

    但是您必须使用一些表达式扩展器,如您所见。 expr.ExpandExpressions() 为了让 LINQ 以正确的方式编译它。

    我用过这个(git link)。这是nuget package。或者你可以自己实现。

    【讨论】:

    • 你不需要空合并运算符,strings 的加法运算符被编译为可以处理nulls 的String.Concat
    • 不。它将通过“+”以通常的字符串连接方式编译,如果其中一个值为 null,则整个字符串将为 null。
    • 正确,我跳过了用于创建对象的表达式也会转换为 SQL 的事实。
    • 我在我的问题中提到了这种方式,问题是我需要一种动态和通用的方式,因为我有几个需要这种选择的类,而且每个类可能都有差异连接字段
    • @Hamid 试试这个,但最好为您使用的每个模型创建一些 dto 或视图模型,以分隔数据层和表示层
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    相关资源
    最近更新 更多