【问题标题】:Entity Framework Code First and linked entities实体框架代码优先和链接实体
【发布时间】:2018-08-03 23:27:46
【问题描述】:

我有 AspNetUser 实体:

public partial class AspNetUser
{
    public string Id { get; set; }

    [Required]
    [StringLength(256)]
    [Index(IsClustered = false, IsUnique = true)]
    public string UserName { get; set; }
    ....

接口:

public interface IProfile
{
    string FirstName { get; set; }
    string LastName { get; set; }
    string Nickname { get; set; }
}

public interface IMembershipEntity
{
    string AspNetUserId { get; set; }
    AspNetUser AspNetUser { get; set; }
}

还有 2 个实体,每个实体都以 FK 的形式链接到 AspNetUser(都实现了 IProfile 和 IMembershipEntity):

public partial class Driver : IMembershipEntity, IProfile
{

    #region IProfile
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Nickname { get; set; }
    #endregion

    #region IMembershipEntity
    public string AspNetUserId { get; set; }
    [ForeignKey("AspNetUserId")]
    public virtual AspNetUser AspNetUser { get; set; }
    #endregion

   ... driver fields


public class User : BaseEntity, IMembershipEntity, IProfile
{
    #region IMembershipEntity
    public string AspNetUserId { get; set; }
    public virtual AspNetUser AspNetUser { get; set; }
    #endregion

    #region IProfile
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Nickname { get; set; }
    #endregion

    .... user fields
}

现在我需要一个需要从 AspNetUser 获取 FirstName/LastName 的方法,如下所示:

        var element = (from i in db.AspNetUsers
                    select new UserElementDomain()
                    {
                        UserId = i.Id,
                        CompanyName = i.Company.Name,
                        FirstName = (get FirstName here),
                        LastName = (get LastName here),
                        RoleName = i.AspNetRoles.FirstOrDefault().Name,
                        SMSnumber = i.SMSnumber,
                        UserName = i.UserName,
                        .....
                    }).FirstOrDefault();

怎么做? 我可以向 AspNetUser 添加 2 个属性,例如:

    public virtual User User { get; set; }
    public virtual Driver Driver { get; set; }

但是怎么说呢,应该是一环还是零环,不用创建UserId/DriverId

即使有了它,我也必须编写如下代码:

FirstName = (i.User!=null)? i.User.FirstName : ((i.Driver!=null)?i.Driver.FirstName : String.Empty)

我不喜欢这段代码,因为当我再添加一个实体时,我必须检查所有代码并再添加一个条件。如何正确执行?可能,使用接口/继承?

【问题讨论】:

  • AspNetUserId 也是UserDriver 表中的PK 吗?换句话说,他们是否实现了Shared Primary Key Association
  • @IvanStoev 不也不能(客户的限制,他希望有单独的 id)
  • 你遇到了麻烦,因为 EF6 对一对一 FK 关系的支持非常有限。这有可能成为 EF Core 吗?
  • @IvanStoev 现在没有机会...
  • 太糟糕了。您必须从界面和实体中牺牲显式 FK 属性 AspNetUserId,并且仅依赖导航属性。参见例如stackoverflow.com/questions/50011305/…stackoverflow.com/questions/43367293/… 等。

标签: c# entity-framework foreign-keys


【解决方案1】:

我以前见过重复的代码,但很少看到重复的数据结构。

根据您当前的代码,如果 User.FirstName="A" & Driver.FirstName="B",则结果仅为“A”。如果您有一个名为“Employee”的新实体,如果您不使用当前样式对其进行硬编码,谁知道哪个名字将是 3 个实体中的真实名字?

您当前的代码可以简化为:

i.User?.FirstName ?? i.Driver?.FirstName ?? i.Whatever?.FirstName ?? String.Empty

但它是您要管理的真实数据吗?

我给你另外两个选择:

  1. 向根实体添加属性,在您的情况下是 AspNetUser:

    public class AspNetUser
    {
    ....
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Nickname { get; set; }
    ....
    }
    
  2. 管理 1 个实体中的常用配置文件

    public class AspNetUser
    {
    ....
    public virtual AspNetUserProfile AspNetUserProfile { get; set; }
    }
    public class AspNetUserProfile
    {
    [Key]
    public string Id { get; set; }
    
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Nickname { get; set; }
    ....
    [ForeignKey("Id")]
    public virtual AspNetUser AspNetUser { get; set; }
    }
    

然后在您的代码中:

   db.AspNetUsers.Select(i => new UserElementDomain()
                {
                    UserId = i.Id,
                    CompanyName = i.Company.Name,
                    FirstName = i.AspNetUserProfile?.FirstName,
                    LastName = i.AspNetUserProfile?.LastName,
                    RoleName = i.AspNetRoles.FirstOrDefault().Name,
                    SMSnumber = i.SMSnumber,
                    UserName = i.UserName,
                    .....
                })

如果 Driver/User/Empolyee 想要获取 FirstName,只需使用:

Empolyee.AspNetUser.AspNetUserProfile?.FirstName

【讨论】:

  • 方法#1 就像今天完成的那样,但它不喜欢我的建筑师。此外,它只是属性的共同部分,Driver 和 User 也有各自的属性
  • 另外,关于i.User?.FirstName ?? i.Driver?.FirstName ?? i.Whatever?.FirstName ?? String.Empty 是编译错误:“表达式树 lambda 可能不包含空传播运算符”
猜你喜欢
  • 1970-01-01
  • 2015-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
相关资源
最近更新 更多