KamikyIT
KamikyIT

Reputation: 314

Entity Framework 1 to Many creates new objects

I'm using EntityFramework for my Microsoft Sql Data Base. First entity is Product:

 public class Product
{
    public Product()
    {
        ProductStories = new HashSet<ProductStory>();
    }

    public int ProductId { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }

    public bool Deleted { get; set; }

    public HashSet<ProductStory> ProductStories { get; set; }
}

And another entity is ProductStory, which stores story about income or outcome of Products.

public class ProductStory
{
    public int ProductStoryId { get; set; }

    public virtual Product.Product Product { get; set; }

    public int Count { get; set; }

     public DateTime DateTime { get; set; }
}

So one Product could be in mane ProductStories, or in none.

I will not show all code(too big), so when I firstly create a single Product instance and save it in DB. Then I create a single ProductStory and reference to property Product to that instance of Product. Then I save this ProductStory, there becomes 2 instances of ProductStory. As I read, and I made this as virtual property:

public virtual Product.Product Product { get; set; }

How this problem could be solved?

I'm using EntityTypeConfiguration for tables configuration.

public class ProductMap : EntityTypeConfiguration<Product>
    {
        public ProductMap()
        {
            ToTable("Products").HasKey(x => x.ProductId);

            Property(x => x.ProductId).IsRequired();
            Property(x => x.Name).IsRequired().HasMaxLength(255).HasColumnName("Name");
                //.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_Name") { IsUnique = true }));
            Property(x => x.Description).IsOptional().HasColumnName("Description");
            Property(x => x.Deleted).HasColumnName("Deleted");
        }
    }

And for ProductStory:

class ProductStoryMap: EntityTypeConfiguration<ProductStory>
    {
        public ProductStoryMap()
        {
            ToTable("ProductStories").HasKey(ps => ps.ProductStoryId);

            Property(ps => ps.ProductStoryId).IsRequired();
            //Property(ps => ps.ProductId).IsRequired().HasColumnName("ProductId");

            Property(ps => ps.Count).HasColumnName("Count");
            Property(ps => ps.DateTime).HasColumnName("DateTime");
        }
    }

Upvotes: 0

Views: 77

Answers (2)

KamikyIT
KamikyIT

Reputation: 314

The solution was about Entity Framework "bug/feature". As I add new ProductStory into DataBase, it attaches the whole graph(including all other entities references and recreates them). So before commiting new ProductStory, I have to set to null all it's navigation properties to avoid recreating.

Upvotes: 0

Camilo Terevinto
Camilo Terevinto

Reputation: 32053

You have some errors in your code:

//Change this:
public HashSet<ProductStory> ProductStories { get; set; }
//For this (virtual is needed here, also use ICollection rather than any specific implementation)
public virtual ICollection<ProductStory> ProductStories { get; set; }

//Change this:
public virtual Product.Product Product { get; set; }
//For this (virtual makes no sense here)
public Product.Product Product { get; set; }

And lastly, ProductStory needs a way to keep the reference to its parent Product. This is what creates the Foreign Key relationship in your database and allows Entity Framework to link the tables. So add this to ProductStory:

public int ProductId { get; set; }

If you are still getting a duplicated object (which may happen), ensure you are setting the ProductId to the ProductStory you are saving.

Upvotes: 1

Related Questions