EF6:添加具有多对多的实体,并且主实体的子项具有多对多

时间:2017-01-21 19:15:53

标签: entity-framework-6

基本上我正在尝试添加一个带有子节点的新实体(Person)(地址);这两个实体确实有很多关系。我正在使用Entity Framework 6.1.3。

  

附加“功能”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图表,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

但即使我认为我正在使用正确的Attach方法来表明数据库中已存在爱好和功能,我也会收到以下错误。

看起来如果我尝试只附加一个featureSet而不是2,那么它可以正常工作。但问题似乎是当为2个地址选择相同的功能时。我甚至试图只附加不同的功能,但随后出现了不同的错误。然后代码尝试添加一个我不想要的新功能。

以下是我正在使用的代码:

public class Person
{
    public int PersonId { get; set; }
    public string Personname { get; set }
    public ICollection<Hobby> Hobbies { get; set; } // Many to Many with Hobbies
    public ICollection<Address> Addresses { get; set; } // One to Many (many side)
}


// Many to Many: Represented in database as PersonHobby (eg. Reading, Writing; User could select multiple hobbies of a person)
public class Hobby
{
    public int HobbyId { get; set; }
    public string Hobbyname { get; set; }
    public ICollection<Person> People { get; set; } // Many-To-Many with Person
}


public class Address
{
    public int AddressId { get; set; }
    public int PersonId { get; set; }
    public string Line1 { get; set; }
    public string City { get; set; }
    public string State { get; set; }

    public Person Person { get; set; }
    public ICollection<Feature> Features { get; set; } 
}


// Many to Many: Represented in database as AddressFeature (e.g Air Conditioning, Central Heating; User could select multiple features of a single address)
public class Feature
{
    public int FeatureId { get; set; }
    public string Featurename { get; set; }
    public ICollection<Address> Addresses { get; set; } // Many-To-Many with Addresses
}

现在,我想在同一张照片中添加一个具有多个地址的新人。

public static Person GetFakePerson()
{
        Person person = new Person();

    person.PersonName = "Peter";
        person.PersonEmail = "demo@demo.com";

    person.Hobbies = new List<Hobby>();
        person.Hobbies.Add(new Hobby { HobbyId = 1 });
        person.Hobbies.Add(new Hobby { HobbyId = 2 });

    person.Addresses = new List<Address>();

    // In real world, the user in GUI will be selecting the following features as the checkboxes within the Address object.
    List<Feature> featureSet_1 = new List<Feature>();
        featureSet_1.Add(new Feature { FeatureId = 1 });
        featureSet_1.Add(new Feature { FeatureId = 2 });
        person.Addresses.Add(new Address { Line1 = "123 St", City = "Fishers", State = "IN", Features = featureSet_1 });

    List<Feature> featureSet_2 = new List<Feature>();
        featureSet_2.Add(new Feature { FeatureId = 1 });
        featureSet_2.Add(new Feature { FeatureId = 2 });
        person.Addresses.Add(new Address { Line1 = "987 Avenue", City = "Carmel", State = "IN", Features = featureSet_2 });

    return person;
}

// PersonService has this method
public int AddPerson(Person person)
{
    try
    {
        using (MyDbContext dbContext = new MyDbContext())
        {
            person.Addresses.ToList().ForEach(y => y.Features.ToList().ForEach(x => dbContext.Features.Attach(x)));

            person.Hobbies.ToList().ForEach(x => dbContext.Hobbies.Attach(x)); // This seems to be working

            dbContext.People.Add(person);

            dbContext.SaveChanges();

            return person.PersonId;
        }
    }
    catch(Exception exp)
    {
        // Catch exception here
    }
}

这就是我调用上述功能的方式:

static void Main(string[] args)
{
    PersonService _personService = new PersonService(); // This class holds the AddPerson()
        Person samplePerson = GetFakePerson();

    int peronId = _personService.AddPerson(samplePerson);
}

1 个答案:

答案 0 :(得分:1)

几乎一切正确。你犯的唯一错误是

List<Feature> featureSet_1 = new List<Feature>();
    featureSet_1.Add(new Feature { FeatureId = 1 });
    featureSet_1.Add(new Feature { FeatureId = 2 });
...

List<Feature> featureSet_2 = new List<Feature>();
    featureSet_2.Add(new Feature { FeatureId = 1 });
    featureSet_2.Add(new Feature { FeatureId = 2 });
...

featureSet_1featureSet_2是两个列表,一起包含四个 Feature个实例。所有EF都知道,这四个实例是附加到上下文的。在第三个实例中,featureSet_2中的第一个实例,它抱怨此主键值已经被&#34;采取&#34;。

您必须将相同的两个Feature实例分配给Address es:

var f1 = new Feature { FeatureId = 1 };
var f2 = new Feature { FeatureId = 2 };
List<Feature> featureSet_1 = new List<Feature> { f1, f2 };
...

List<Feature> featureSet_2 = new List<Feature>  { f1, f2 };
...

(如果您将featureSet_1两次分配给两个地址,也许EF会很高兴。