实体框架参考属性

时间:2016-03-14 09:56:09

标签: c# entity-framework

我正在使用Entity Framework 6。

我正在使用两个班级:

public partial class StateProvince
{

     public StateProvince()
    {
        Addresses = new HashSet<Address>();
    }

    public int StateProvinceID { get; set; }

    public string StateProvinceCode { get; set; }

    public string CountryRegionCode { get; set; }

    public bool IsOnlyStateProvinceFlag { get; set; }

    public string Name { get; set; }

    public int TerritoryID { get; set; }

    public Guid rowguid { get; set; }

    public DateTime ModifiedDate { get; set; }

    public ICollection<Address> Addresses { get; set; }

    public CountryRegion CountryRegion { get; set; }

}

public partial class CountryRegion
{
    public CountryRegion()
    {
        StateProvinces = new HashSet<StateProvinceTlb>();
    }

    public string CountryRegionCode { get; set; }

    public string Name { get; set; }

    public DateTime ModifiedDate { get; set; }

    public virtual ICollection<StateProvince> StateProvinces { get; set;}
}

我希望能够运行一个返回StateProvince列表的查询,但也包含CountryRegion中的名称。我们的想法是,在编辑屏幕上,用户将选择或编辑CountryRegionCode,但名称将显示在一个无法编辑的字段旁边,仅供参考。

我尝试将属性作为无映射字段添加到StateProvince并引用CountryRegion上的属性,如下所示:

    [NotMapped]
    public string CountryName
    {
        get{ return CountryRegion.Name;}
    }

但问题是必须加载CountryRegion才能使其正常工作,我的目标是不必加载整个CountryRegion对象。

我也尝试在我的查询中设置它:

            List<StateProvince> statP = context.StateProvinces.Select(s => new StateProvince() {s, CountryName = context.CountryRegions.Where(x => x.CountryRegionCode == s.CountryRegionCode).Select(x => x.Name).FirstOrDefault() }).ToList();

但这不起作用,因为返回的对象由StateProvince对象和单独的CountryName属性组成。

我甚至尝试过单独设置每个字段,如:

            List<StateProvince> statP = context.StateProvinces.Select(s => new StateProvince() { Name = s.Name, TerritoryID = s.TerritoryID, rowguid = s.rowguid, ModifiedDate = s.ModifiedDate, Addresses=s.Addresses, CountryRegion=s.CountryRegion, CountryName = context.CountryRegions.Where(x => x.CountryRegionCode == s.CountryRegionCode).Select(x => x.Name).FirstOrDefault() }).ToList();

但这会再次导致整个CountryRegion对象加载,如果我将这些属性保留,则抛出异常。此外,对于较大的实体,这将难以维护。

TLDR;这个版本:实体框架中是否有一种方法可以将一个类映射到一个表,但在该类上有一个属性引用另一个表上的属性而不必检索子表上的所有内容?

我进行了搜索和搜索,并且无法真正找到涵盖这种特定情景的内容。我对Entity Framework很新,我觉得我错过了一些明显的东西。任何帮助将不胜感激!!

这就是我提出的解决问题的方法。

首先,我将CountryRegion表拆分为两个单独的类

public partial class CountryRegionHeader
{
    public CountryRegionHeader()
    {
       StateProvinces = new HashSet<StateProvinceTlb>();
    }

    public string CountryRegionCode { get; set; }

    public string Name { get; set; }
}

public partial class CountryRegionDetail
{
    public CountryRegionDetail()
    {
        StateProvinces = new HashSet<StateProvinceTlb>();
    }

    public string CountryRegionCode { get; set; }


    public DateTime ModifiedDate { get; set; }

    public virtual ICollection<StateProvince> StateProvinces { get; set;}

    public virtual CountryRegion CountryRegion {get;set;}

}

然后我将新类的属性添加到StateProvince类

[ForeignKey("CountryRegionCode)]
public CountryRegionHeader CountryRegionHeader {get;set;}

[ForeignKey("CountryRegionCode)]
public CountryRegionDetail CountryRegionDetail {get;set;}

然后我将DBSets添加到CountryRegionHeader和CountryRegionDetail的模型上下文中,并使用OnModelCreating方法中的流畅API将它们绑定在一起

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<CountryRegionHeader>()
        .HasRequired(e => e.CountryRegionDetail)
        .WithRequiredPrincipal();
}

除此之外,我还创建了另一个名为CountryRegion的类,它具有Header和Detail以及Header和Detail对象本身的所有属性。这些属性实际上指向标题和细节。这实际上不是必需的,但它使代码更清晰,更易于使用。此外,当将数据发送到Web客户端时,我只能序列化CountryRegion对象并排除Header和Detail对象。所以基本上我的CountryRegion类看起来像这样:

public Class CountryRegion
{
    public CountryRegionHeader Header;
    public CountryRegionDetail Detail;

    public CountryRegionCode
    {
       //need some special logic here for the key since both Header or
       //Detail share the primary key and both may not be loaded
       get
       {
           if (Header != null)
               return Header.CountryRegionCode;
           else
               return Detail.CountryRegionCode; 
        }
        set
        {
            if (Header != null) Header.CountryRegionCode = value;
            if (Detail != null) Detail.CountryRegionCode = value;
        }
    }

    public string Name
    {
        get
        {
            return Header.Name;
        }
        set
        {
            Header.Name = value;
        }

    }

    public DateTime ModifiedDate
    {
        get
        {
            return Detail.ModifiedDate ;
        }
        set
        {
            Detail.ModifiedDate = value;
        }

    }

    public virtual ICollection<StateProvince> StateProvinces
    {
        get
        {
            return Detail.StateProvinces ;
        }
        set
        {
            Detail.StateProvinces = value;
        }

    }

}

所以,现在,当我查询时,我可以做类似的事情:

List<StateProvince> query =       db.StateProvince.Include(o=>o.CountryRegionHeader).ToList();

我只检索我需要的数据而不检索整个CountryRegion记录

另外,如果我只使用CountryRegion,我可以这样查询:

List<CountryRegion> query = (from a in db.CountryRegionHeader join b in    db.CountryRegionDetail on a.CountryRegionCode equals b.CountryRegionCode select new Employee(){Header = a, Detail = b}).ToList(); 

2 个答案:

答案 0 :(得分:2)

这就是我提出的解决问题的方法。

首先,我将CountryRegion表拆分为两个单独的类

public partial class CountryRegionHeader
{
    public CountryRegionHeader()
    {
       StateProvinces = new HashSet<StateProvinceTlb>();
    }

    public string CountryRegionCode { get; set; }

    public string Name { get; set; }
}

public partial class CountryRegionDetail
{
    public CountryRegionDetail()
    {
        StateProvinces = new HashSet<StateProvinceTlb>();
    }

    public string CountryRegionCode { get; set; }


    public DateTime ModifiedDate { get; set; }

    public virtual ICollection<StateProvince> StateProvinces { get; set;}

    pubic virtual CountryRegion CountryRegion {get;set;}

}

然后我将新类的属性添加到StateProvince类

[ForeignKey("CountryRegionCode)]
public CountryRegionHeader CountryRegionHeader {get;set;}

[ForeignKey("CountryRegionCode)]
public CountryRegionDetail CountryRegionDetail {get;set;}

然后我将DBSets添加到CountryRegionHeader和CountryRegionDetail的模型上下文中,并使用OnModelCreating方法中的流畅API将它们绑定在一起

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<CountryRegionHeader>()
        .HasRequired(e => e.CountryRegionDetail)
        .WithRequiredPrincipal();
}

除此之外,我还创建了另一个名为CountryRegion的类,它具有Header和Detail以及Header和Detail对象本身的所有属性。这些属性实际上指向标题和细节。这实际上并不是必需的,但它使代码更清晰,更易于使用。此外,当将数据发送到Web客户端时,我只能序列化CountryRegion对象并排除Header和Detail对象。所以基本上我的CountryRegion类看起来像这样:

public Class CountryRegion
{
    public CountryRegionHeader Header;
    public CountryRegionDetail Detail;

    public CountryRegionCode
    {
       //need some special logic here for the key since both Header or
       //Detail share the primary key and both may not be loaded
       get
       {
           if (Header != null)
               return Header.CountryRegionCode;
           else
               return Detail.CountryRegionCode; 
       }
       set
       {
           if (Header != null) Header.CountryRegionCode = value;
           if (Detail != null) Detail.CountryRegionCode = value;
       }
   }

   public string Name
   {
       get
       {
           return Header.Name;
       }
       set
       {
           Header.Name = value;
       }

   }

   public DateTime ModifiedDate
   {
       get
       {
            return Detail.ModifiedDate ;
       }
       set
       {
            Detail.ModifiedDate = value;
       }

   }

   public virtual ICollection<StateProvince> StateProvinces
   {
      get
      {
           return Detail.StateProvinces ;
      }
      set
      {
           Detail.StateProvinces = value;
      }

   }

}

所以,现在,当我查询时,我可以做类似的事情:

List<StateProvince> query =       db.StateProvince.Include(o=>o.CountryRegionHeader).ToList();

我只检索我需要的数据而不检索整个CountryRegion记录

另外,如果我只使用CountryRegion,我可以这样查询:

List<CountryRegion> query = (from a in db.CountryRegionHeader join b in    db.CountryRegionDetail on a.CountryRegionCode equals b.CountryRegionCode select new Employee(){Header = a, Detail = b}).ToList(); 

答案 1 :(得分:0)

实现此目的的一种方法是在数据库中添加一个计算列,在StateProvince上为您提供CountryRegion名称。

有了这一切,您只需要请求StateProvince表,您的数据库服务器将为您提供相关的CountryRegion名称。

修改

在您发表评论后,我有了另一个想法。

为您的用法创建一个类:

public class StateProvinceEdition : StateProvince
{
    public string CountryRegionName { get; set; }

    public StateProvinceEdition(StateProvince stateProvince, string countryRegionName)
    {
        this.StateProvinceID = stateProvince.StateProvinceID;
        // And so on ...

        // Adding country region name
        this.CountryRegionName = countryRegionName;
    }
}

然后,您需要使用Linq将查询结果投影到对象中:

 List<StateProvinceEdition> statP = context.StateProvinces.Select(s => new StateProvince(s, s.CountryRegion.Name)).ToList();

我没有数据库来测试它,所以如果EF抛出关于构造函数的异常,请尝试将Select和ToList语句切换为首先从数据库加载对象,然后将结果投影到自定义类中。

第二次修改

与第一个想法类似,您可以在数据库中为您的目的创建一个视图,然后使用Entity Framework查询此视图。使用此解决方案,除了添加视图之外,您无需更改数据库。