Entity framework EF Hashset集合-重写Equals和GetHashCode

Entity framework EF Hashset集合-重写Equals和GetHashCode,entity-framework,Entity Framework,我与EF中的联接表有多对多关系 在其他问题中,我似乎有一些建议,建议对多对多关系使用Hashset集合类型,并覆盖Equals()和GetHashCode() 为什么要使用Hashset? public class ChartQuery { public int ChartQueryId { get; set; } public virtual ICollection<UserChartQuery> Users { get; set; } ...more...

我与EF中的联接表有多对多关系

在其他问题中,我似乎有一些建议,建议对多对多关系使用
Hashset
集合类型,并覆盖Equals()和GetHashCode()


为什么要使用Hashset?

public class ChartQuery
{
    public int ChartQueryId { get; set; }
    public virtual ICollection<UserChartQuery> Users { get; set; }
   ...more...
}

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<UserChartQuery> SavedChartQueries { get; set; }
    ...more...
}

public class UserChartQuery
{
    public int UserId { get; set; }
    public int ChartQueryId { get; set; }

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

}
我如何覆盖这些方法,以及这能实现什么?

public class ChartQuery
{
    public int ChartQueryId { get; set; }
    public virtual ICollection<UserChartQuery> Users { get; set; }
   ...more...
}

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<UserChartQuery> SavedChartQueries { get; set; }
    ...more...
}

public class UserChartQuery
{
    public int UserId { get; set; }
    public int ChartQueryId { get; set; }

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

}
公共类ChartQuery
{
公共int ChartQueryId{get;set;}
公共虚拟ICollection用户{get;set;}
更多
}
公共类用户
{
public int UserId{get;set;}
公共字符串用户名{get;set;}
公共虚拟ICollection SavedChartQueries{get;set;}
更多
}
公共类UserChartQuery
{
public int UserId{get;set;}
公共int ChartQueryId{get;set;}
公共虚拟用户用户{get;set;}
公共虚拟图表查询图表查询{get;set;}
}

我为什么要使用Hashset?

public class ChartQuery
{
    public int ChartQueryId { get; set; }
    public virtual ICollection<UserChartQuery> Users { get; set; }
   ...more...
}

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<UserChartQuery> SavedChartQueries { get; set; }
    ...more...
}

public class UserChartQuery
{
    public int UserId { get; set; }
    public int ChartQueryId { get; set; }

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

}
你不应该。只要正确映射,多对多行的唯一性将在数据库级别强制执行。在应用程序级别实施它几乎没有什么好处

我如何覆盖这些方法,以及这能实现什么?

public class ChartQuery
{
    public int ChartQueryId { get; set; }
    public virtual ICollection<UserChartQuery> Users { get; set; }
   ...more...
}

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<UserChartQuery> SavedChartQueries { get; set; }
    ...more...
}

public class UserChartQuery
{
    public int UserId { get; set; }
    public int ChartQueryId { get; set; }

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

}
实体框架中的多对多关系没有表示关系的不同实体,因此没有实体可以覆盖
Equals()
GetHashCode()

您可以定义一个实体来满足多对多关系,但从对象模型的角度来看,这有点做作和丑陋。如果要执行此操作,您将覆盖
Equals()
GetHashCode()
,将equality定义为参与的键彼此相等,并且哈希代码将是参与键的唯一组合

更新

以表示多对多关系的实体为例,这就是如何实现
Equals
GetHashCode
,以便在HashSet中正确使用它的方法:

public class UserChartQuery
{
    public int UserId { get; set; }
    public int ChartQueryId { get; set; }

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

        protected bool Equals(UserChartQuery other)
    {
        return UserId == other.UserId && ChartQueryId == other.ChartQueryId;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((UserChartQuery) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (UserId*397) ^ ChartQueryId;
        }
    }
}
如上所述,我建议使用更自然和内置的方式在EF中建立多对多关系:

public class ChartQuery
{
    public int ChartQueryId { get; set; }
    public virtual ICollection<User> Users { get; set; }
   ...more...
}

public class User
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public virtual ICollection<ChartQuery> SavedChartQueries { get; set; }
    ...more...
}
公共类ChartQuery
{
公共int ChartQueryId{get;set;}
公共虚拟ICollection用户{get;set;}
更多
}
公共类用户
{
public int UserId{get;set;}
公共字符串用户名{get;set;}
公共虚拟ICollection SavedChartQueries{get;set;}
更多
}
在映射中,然后将多对多关系定义为(在DbContext OnModelCreating覆盖中):

builder.Entity()
.HasMany(cq=>ucq.Users)
.with many(u=>u.savedchart查询);

在这两种情况下,我真的认为使用HashSet是没有必要的。即使实体满足多对多关系,数据库也将强制复合键的唯一性。

感谢您的响应。“您可以定义一个实体来满足多对多关系”。这不是我使用表示联接表的
UserChartQuery
实体所做的吗?如果是这种情况,我正在寻找一个代码示例,如何重写这些方法,因为我找不到。另一方面,如果你建议我在没有联接表的情况下使用不同的映射,那么请告诉我如何配置这样的映射,因为我已经为此奋斗了一段时间,直到我用联接表得到了我想要的。是的,这正是你用UserChartQuery所做的。对不起,我第一次没注意到。我已经更新了答案。如果你还有任何问题,请告诉我。谢谢你的更新,谢谢你的。最后一点,您能想到在应用程序级别强制实现唯一性的任何好处吗?我看到的好处是,在将两个
UserChartQuery
对象添加到
savedchartquerys
Users
集合后,尝试持久化两个键相同的
UserChartQuery
对象时不会出现异常。使用哈希集,集合中不可能存在重复项。这样做的代价是将集合声明为
HashSet
,而不是
ICollection
,这反过来会破坏实体框架中的代理生成。一个解决方法是为
UserChartQuery
创建一个IEqualityComparer,并使用LINQ的
Distinct
方法清除任何重复。布莱恩。。。“使用哈希集,集合中不可能存在重复项”是EF以这种方式本机实现哈希集的主要原因之一。例如,如果您先进行db设计,EF将使用Hashset实现生成类。是的,但这是有代价的。