C# 并创建了一个修复程序。谢谢你一直思考!通常,为了避免这种异常,在EF实体上公开FK属性通常是一个好做法。不过,您仍然应该在实体上实现IEquatable接口,因为它处理的集合太多,而动态代理意味着ReferenceEquals比较将返回false。 pub

C# 并创建了一个修复程序。谢谢你一直思考!通常,为了避免这种异常,在EF实体上公开FK属性通常是一个好做法。不过,您仍然应该在实体上实现IEquatable接口,因为它处理的集合太多,而动态代理意味着ReferenceEquals比较将返回false。 pub,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,并创建了一个修复程序。谢谢你一直思考!通常,为了避免这种异常,在EF实体上公开FK属性通常是一个好做法。不过,您仍然应该在实体上实现IEquatable接口,因为它处理的集合太多,而动态代理意味着ReferenceEquals比较将返回false。 public class Language { [JsonProperty("iso_639_1")] public string Iso { get; set; } [JsonProperty("name")] p


并创建了一个修复程序。谢谢你一直思考!通常,为了避免这种异常,在EF实体上公开FK属性通常是一个好做法。不过,您仍然应该在实体上实现
IEquatable
接口,因为它处理的集合太多,而动态代理意味着ReferenceEquals比较将返回false。
public class Language
{
    [JsonProperty("iso_639_1")]
    public string Iso { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is Language))
        {
            return false;
        }

        return ((Language)obj).Iso == Iso;
    }

    public override int GetHashCode()
    {
        return Iso.GetHashCode();
    }
}
var localLanguages = context.Languages.ToList();
var existingLanguages = localLanguages.Union(movie.SpokenLanguages);
var newLanguages = localLanguages.Except(existingLanguages).ToList();
newLanguages.AddRange(existingLanguages);
movie.SpokenLanguages = newLanguages;
var localLanguages = context.Languages.ToList();
foreach (var language in movie.SpokenLanguages)
{
    if (localLanguages.Contains(language))
    {
        context.Languages.Attach(language);
        // no difference between both approaches
        context.Entry(language).State = EntityState.Unchanged;
    }
}
{
    "iso_639_1": "en",
    "name": "English"
}
public class Language : IEquatable<Language>
{
    [JsonProperty("iso_639_1")]
    public string Iso { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        return Equals(other as Language);
    }

    public bool Equals(Langauge other)
    {
        // instance is never equal to null
        if (other == null) return false;

        // when references are equal, they are the same object
        if (ReferenceEquals(this, other)) return true;

        // when either object is transient or the id's are not equal, return false
        if (IsTransient(this) || IsTransient(other) ||
            !Equals(Iso, other.Iso)) return false;

        // when the id's are equal and neither object is transient
        // return true when one can be cast to the other
        // because this entity could be generated by a proxy
        var otherType = other.GetUnproxiedType();
        var thisType = GetUnproxiedType();
        return thisType.IsAssignableFrom(otherType) ||
            otherType.IsAssignableFrom(thisType);
    }

    public override int GetHashCode()
    {
        return Iso.GetHashCode();
    }

    private static bool IsTransient(Language obj)
    {
        // an object is transient when its id is the default
        // (null for strings or 0 for numbers)
        return Equals(obj.Iso, default(string));
    }

    private Type GetUnproxiedType()
    {
        return GetType(); // return the unproxied type of the object
    }
}
var localLanguages = context.Languages.ToList(); // dynamic proxies
foreach (var language in movie.SpokenLanguages) // non-proxied
{
    if (localLanguages.Any(x => x.Equals(language)))
    {
        context.Entry(language).State = EntityState.Modified;
    }
}
INSERT [dbo].[MovieLanguages]([MovieId], [LanguageId])
VALUES (@0, @1)

-- @0: '2' (Type = Int32)  
-- @1: '0' (Type = Int32)
var localLanguages = _context.Languages.ToList();
foreach (var language in movie.SpokenLanguages)
{
    var localLanguage = localLanguages.Find(x => x.Iso == language.Iso);
    
    if (localLanguage != null)
    {
        language.Id = localLanguage.Id;
        _context.Entry(localLanguage).State = EntityState.Detached;
        _context.Languages.Attach(language);
    }
}