【问题标题】:Entity Framework - Get 'fake' navigation property within one query实体框架 - 在一个查询中获取“假”导航属性
【发布时间】:2013-09-26 07:24:14
【问题描述】:

我有一个Product 表,它没有与translation 表定义任何关系。我将Translation 属性添加到Product POCO 作为[NotMapped]

**我的产品 POCO:**

public partial class Product
{
    public int ProductID { get; set; }

    public double Price { get; set; }

    [NotMapped]
    public virtual Translation Translation{ get; set; }

    /** Other properties **/
}

我还有一个Translation 表,正如名字所说,它包含所有的翻译。 现在,通过提供LanguageIDTranslationOriginIDValueID三个参数,可以从数据库中检索到正确的translation

  • LanguageID:来自用户定义的语言的 ID。
  • TranslationOriginID:简单地说,“哪个表包含我想要翻译的实体?”换句话说,这个 ID 指向另一个包含所有可能来源的表。原点是可以具有translation 的表/实体。例如:本例中的来源是Product
  • ValueID:这是我想要 translation 的实体的 ID。

我的TranslationPOCO:

public partial class Translation
{
    public int TranslationID { get; set; }

    public byte LanguageID { get; set; }

    public short TranslationOriginID { get; set; }

    public int ValueID { get; set; }

    public string TranslationValue { get; set; }

   /** Other properties **/

    public virtual TranslationOrigin TranslationOrigin { get; set; }

    public virtual Language Language { get; set; }
}

当我想用Translation 检索所有产品时,我执行以下代码:

List<Product> products = context.Products.ToList();

 foreach (Product product in products)
 {
      product.Translation = context.Translations.FirstOrDefault(y => y.LanguageID == 1 && y.TranslationOriginID == 2 && y.ValueID == product.ProductID);
 }

如您所见,我为列表中的每个产品执行另一个查询以获取翻译。

我的问题: 是否可以在一个查询中获得所有产品及其翻译?甚至当我选择product 时我会自动检索正确的翻译?

我已经尝试过.Include().Select()。它没有工作,也许我做错了什么? 我也试过this method,也没用。

顺便说一句,我使用 .NET 4 的实体框架 5(所以,实体框架 4.4)。

提前致谢。

问候 洛顿


回答

通过Ed Chapel给出的例子,我想出了一个解决方案。

return (from p in context.Products
            join t in context.Translations
            on new
            {
                Id = p.ProductID,
                langId = languageID,
                tOriginId = translationOriginID
            }
            equals new
            {
                Id = d.ValueID,
                langId = d.LanguageID,
                tOriginId = d.TranslationOriginID
            }
            into other
            from x in other.DefaultIfEmpty()
            select new
            {
                Product = p,
                Translation = x
            })
            .ToList().ConvertAll(x => new Product()
            {
                Code = x.Product.Code,
                Translation = x.Translation,
                /** Other properties **/
            });

【问题讨论】:

    标签: c# linq entity-framework


    【解决方案1】:

    在大多数情况下,我不喜欢正确的 LINQ。但是,join 是 LINQ 比扩展方法简单的一种情况:

    from p in context.Products
    join t in context.Translations
        on t.ValueID equals p.ValueID
           && t.LanguageID == 1
           && t.TranslationOriginID == 2
        into joinT
    from x in joinT
    select new { 
                   Product = p,
                   Translation = t,
               };
    

    然后循环遍历结果设置x.Product.Translation = x.Translation

    【讨论】:

    • 你是对的。您在示例中犯的唯一错误是在连接语句中使用了多个参数。您可以使用正确的解决方案查看我编辑的帖子。
    【解决方案2】:

    首先,您应该意识到您的翻译表的结构不像 dba 所希望的那样
    您有非强制关系,因为根据 OriginId,您的 valueId 引用了不同的表。
    因此,您不能使用延迟加载或 EF 中的包含。
    在这一点上,我最好的想法是手动加入匿名类型的表(包括你的 originId)。之后,您可以遍历结果以设置翻译属性

    结果如下所示:

    var data =   from p in context.Products
                 join pt in context.Translations on new{p.Id,2} equals new {pt.ValueId, pt.OriginId} into trans
                 select new {p, trans};
    var result = data.ToList().Select( a =>
                    {
                        a.p.Translations = a.trans;
                        return a.p;
                    }).ToList();
    

    【讨论】:

      【解决方案3】:

      Ed Chapel 提出的解决方案为例,我想出了这个。

       return (from p in context.Products
                      join t in context.Translations
                      on new
                      {
                          Id = p.ProductID,
                          langId = languageID,
                          tOriginId = translationOriginID
                      }
                      equals new
                      {
                          Id = d.ValueID,
                          langId = d.LanguageID,
                          tOriginId = d.TranslationOriginID
                      }
                      into other
                      from x in other.DefaultIfEmpty()
                      select new
                      {
                          Product = p,
                          Translation = x
                      })
                      .ToList().ConvertAll(x => new Product()
                      {
                          Code = x.Product.Code,
                          Translation = x.Translation,
                          /** Other properties **/
                      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多