Добавление и обновление сущностей с помощью Entity Framework

в моем последнем проекте я сначала использовал код Entity Framework 5. Я завершил свой проект, но испытал много боли в процессе разработки.

Я попытался объяснить свою боль ниже:

У меня было несколько классов данных в моем логическом слое доступа к данным, таком как продукт, ProductCategory, Order, Company, Manufacturer и т. д... Каждый класс имеет некоторые ссылки на некоторые другие классы. Например, экземпляр продукта имеет свойство ProductCategory.

внутри добавить и Обновление методов классов объектов доступа к данным я устанавливаю состояния каждого свойства (кроме примитивных типов) неизмененными или измененными в контексте. Ниже приведена часть метода обновления некоторого класса dao:

context.Entry(entity).State = System.Data.EntityState.Modified;
if (entity.Category != null)
    context.Entry(entity.Category).State = System.Data.EntityState.Unchanged;

if (entity.Manufacturer != null)
    context.Entry(entity.Manufacturer).State = System.Data.EntityState.Unchanged;

foreach (var specificationDefinition in entity.SpecificationDefinitions)
{
    context.Entry(specificationDefinition).State = System.Data.EntityState.Unchanged;
    foreach (var specificationValue in specificationDefinition.Values)
    {
        context.Entry(specificationValue).State = System.Data.EntityState.Unchanged;
    }
}

этот код выглядит так. Некоторые из моих методов добавления или обновления составляют около 30 строк кода. Я думаю, что я делаю что-то неправильно, добавление или обновление сущности не должно быть такой болью, но когда я не устанавливаю состояния объектов, я либо получаю исключение, либо повторяющиеся записи в базе данных. Действительно ли мне нужно установить состояние каждого свойства, которое сопоставляется с базой данных?

2 ответов


вы можете заменить код:

context.Products.Attach(entity);
context.Entry(entity).State = System.Data.EntityState.Modified;

причина, по которой это то же самое (если связанные сущности не были уже присоединены к контексту в другом состоянии, чем Unchanged раньше) заключается в том, что Attach ставит entity в том числе все связанные объекты в графе объектов в контекст в состоянии Unchanged. Установка состояния Modified потом entity изменяет только состояние продукта (а не связанных объектов) из Unchanged to Modified.


Хорошо, тогда ты просто делаешь что-то не так. В дополнение к моему комментарию я создал образец для Вашего, который показывает, что EF не создает дубликаты по умолчанию.

у меня есть два класса:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ProductCategory Category { get; set; }
    public decimal Price { get; set; }
}

public class ProductCategory
{
    public int Id { get; set; }
    public string Name { get; set; }
}

одном контексте:

public class MyContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<ProductCategory> ProductCategories { get; set; }

    public MyContext()
        : base("name=MyContext")
    {
    }

    public MyContext(string nameOrConnectionString)
        : base(nameOrConnectionString)
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        Database.SetInitializer<MyContext>(null);

        // Table mappings
        modelBuilder.Entity<Product>().ToTable("Product");
        modelBuilder.Entity<ProductCategory>().ToTable("ProductCategory");

        base.OnModelCreating(modelBuilder);
    }
}

затем один класс инициализатора (это может наследовать от других стратегий, если вы хотите):

public class InitDb<TContext> : DropCreateDatabaseAlways<TContext>
    where TContext : DbContext
{
}

основная программа:

    static void Main(string[] args)
    {
        var prodCat = new ProductCategory()
        {
            Name = "Category 1"
        };

        var prod = new Product()
        {
            Name = "Product 1",
            Category = prodCat,
            Price = 19.95M
        };

        using (var context = new MyContext())
        {
            var initializer = new InitDb<MyContext>();
            initializer.InitializeDatabase(context);

            Console.WriteLine("Adding products and categories to context.");
            context.ProductCategories.Add(prodCat);
            context.Products.Add(prod);

            Console.WriteLine();
            Console.WriteLine("Saving initial context.");
            context.SaveChanges();
            Console.WriteLine("Context saved.");

            Console.WriteLine();
            Console.WriteLine("Changing product details.");
            var initProd = context.Products.Include(x => x.Category).SingleOrDefault(x => x.Id == 1);
            PrintProduct(initProd);
            initProd.Name = "Product 1 modified";
            initProd.Price = 29.95M;
            initProd.Category.Name = "Category 1 modified";
            PrintProduct(initProd);

            Console.WriteLine();
            Console.WriteLine("Saving modified context.");
            context.SaveChanges();
            Console.WriteLine("Context saved.");

            Console.WriteLine();
            Console.WriteLine("Getting modified product from database.");
            var modProd = context.Products.Include(x => x.Category).SingleOrDefault(x => x.Id == 1);
            PrintProduct(modProd);

            Console.WriteLine();
            Console.WriteLine("Finished!");
            Console.ReadKey();
        }


    }

    static void PrintProduct(Product prod)
    {
        Console.WriteLine(new string('-', 10));
        Console.WriteLine("Id      : {0}", prod.Id);
        Console.WriteLine("Name    : {0}", prod.Name);
        Console.WriteLine("Price   : {0}", prod.Price);
        Console.WriteLine("CatId   : {0}", prod.Category.Id);
        Console.WriteLine("CatName : {0}", prod.Category.Name);
        Console.WriteLine(new string('-', 10));
    }

это приводит к следующей консоли вывод:

Adding products and categories to context.

Saving initial context.
Context saved.

Changing product details.
----------
Id      : 1
Name    : Product 1
Price   : 19,95
CatId   : 1
CatName : Category 1
----------
----------
Id      : 1
Name    : Product 1 modified
Price   : 29,95
CatId   : 1
CatName : Category 1 modified
----------

Saving modified context.
Context saved.

Getting modified product from database.
----------
Id      : 1
Name    : Product 1 modified
Price   : 29,95
CatId   : 1
CatName : Category 1 modified
----------

Finished!

кроме того, при просмотре в SQL Server Management Studio это решение создало (и обновило) только один продукт и одну категорию.

конечно, вы должны работать с репозиториями для извлечения, обновления и удаления данных и единица работы. Они были исключены из примера.

Итак, если вы не публикуете код, мы не можем помочь вам намного дальше : -)