EF вопрос
От: Kaifa Россия  
Дата: 25.06.19 11:51
Оценка: :)
разбираю пример из книжки

    public class Product
    {
        [Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int ProductID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public string Category { get; set; }
    }


    public class Order
    {
        [BindNever]
        public int OrderId { get; set; }

        [BindNever]
        public ICollection<CartLine> Lines { get; set; }

        [Required ( ErrorMessage = "Please enter a name" )]
        public string Name { get; set; }

        [Required ( ErrorMessage = "Please enter first address line")]
        public string Line1 { get; set; }
        public string Line2 { get; set; }
        public string Line3 { get; set; }

        [Required (ErrorMessage = "Please enter city name")]
        public string City { get; set; }

        [Required (ErrorMessage = "Please enter state name")]
        public string State { get; set; }
        public string Zip { get; set; }

        [Required (ErrorMessage = "Please enter country name")]
        public string Country { get; set; }

        public bool GiftWrap { get; set; }
    }

    public class ApplicationDbContext: DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
        }

        public DbSet<Product> Products { get; set; }
        public DbSet<Order> Orders { get; set; }
    }

    public class EFOrderRepository : IOrderRepository
    {
        private ApplicationDbContext context;

        public EFOrderRepository(ApplicationDbContext ctx)
        {
            this.context = ctx;
        }

        public IEnumerable<Order> Orders => context.Orders
            .Include(o => o.Lines)
            .ThenInclude(p => p.Product);

        public void SaveOrder(Order order)
        {
            context.AddRange(order.Lines.Select(l => l.Product));
            if (order.OrderId == 0)
            {
                context.Orders.Add(order);
            }
            
            context.SaveChanges();
        }

    }


    public class EFProductRepository: IProductRepository
    {
        private ApplicationDbContext context;

        public EFProductRepository(ApplicationDbContext ctx)
        {
            this.context = ctx;
        }

        public IEnumerable<Product> Products => this.context.Products;
    }



при выполнении context.SaveChanges() из EFOrderRepository, получается ошибка

Microsoft.EntityFrameworkCore.DbUpdateException
HResult=0x80131500
Message=An error occurred while updating the entries. See the inner exception for details.
Source=Microsoft.EntityFrameworkCore.Relational
StackTrace:
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IReadOnlyList`1 entries)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at SportsStore.Models.EFOrderRepository.SaveOrder(Order order) in D:\Prj\CSharp\SportsStore\SportsStore\Models\EFOrderRepository.cs:line 30
at SportsStore.Controllers.OrderController.Checkout(Order order) in D:\Prj\CSharp\SportsStore\SportsStore\Controllers\OrderController.cs:line 33
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()

Inner Exception 1:
SqlException: Cannot insert explicit value for identity column in table 'Products' when IDENTITY_INSERT is set to OFF.


собственно пытаюсь понять, как ему сказать, чтобы первичный ключ явно не пытался вставлять? и вообще не понимаю, что он пытается делать с таблицей Products?
в профайлере выполняется

exec sp_executesql N'SET NOCOUNT ON;
INSERT INTO [Products] ([ProductID], [Category], [Description], [Name], [Price])
VALUES (@p0, @p1, @p2, @p3, @p4);
',N'@p0 int,@p1 nvarchar(4000),@p2 nvarchar(4000),@p3 nvarchar(4000),@p4 decimal(5,2)',@p0=1,@p1=N'Watersports',@p2=N'Boat for one person',@p3=N'Kayak',@p4=275.00



нафига?
Отредактировано 25.06.2019 12:03 Kaifa . Предыдущая версия .
Re: EF вопрос
От: Danchik Украина  
Дата: 25.06.19 14:09
Оценка: 2 (1) +2 :)
Здравствуйте, Kaifa, Вы писали:

[Skip]

K>нафига?


Вот без малейшего, предполагаю из-за того что вы пытаесь вставить Tracking entity, и не ясно как вы это вызываете — это, блин, может быть важно. Я вижу что без ста грамм этим пользоваться сложно.
Зачем тут репозиторий, еще сложнее сказать. Я бы эту книжку закопал подальше.

Возьмите примеры из доков, они более менее актуальны. EF Core настолько сильно меняется, что книжку годичной давности, можно выкидывать на помойку.

Вот эта вот чушь
 public IEnumerable<Order> Orders => context.Orders
            .Include(o => o.Lines)
            .ThenInclude(p => p.Product);

Всегда! грузит продукты, даже если они вам не нужны. Пожалейте SQL Server. Также оно автоматически трекает изменения этих обьектов.

Даже если вы дернулись в сторону репозитория, подумайте нужен ли вам Change Tracking
context.Orders
            .Include(o => o.Lines)
            .ThenInclude(p => p.Product).AsNoTracking()


Выставляйте наружу IQueryable, а не IEnumerable, и вы сможете контролировать что включать, и что трекать. Но тут опять же резонный вопрос, зачем тогда нужен репозиторий. Нужны только запросы.
Re[2]: EF вопрос
От: Kaifa Россия  
Дата: 26.06.19 05:03
Оценка:
D>Вот без малейшего, предполагаю из-за того что вы пытаесь вставить Tracking entity, и не ясно как вы это вызываете — это, блин, может быть важно. Я вижу что без ста грамм этим пользоваться сложно.
D>Зачем тут репозиторий, еще сложнее сказать. Я бы эту книжку закопал подальше.

книжка Фримен А. — ASP.NET Core MVC с примерами на C# для профессионалов — 2017. да. несколько устаревшая.
она про мвц, а не EF. видимо поэтому такой код. про EF у меня есть его книжка 2019, в предисловии он написал, что потребуется знания мвц (которых у меня нет). соответственно, читать начал с той, чтобы понять на уровне концепций, а углубляться уже потом. в книжке создается очень примитивное приложение — магазин на рэйзор.
собственно исходный приложил. может сразу видно будет где косяк? (у меня EF на уровне написания несложных запросов, как оно там живет внутри для меня пока недоступно, и я обязательно погружусь, просто надо с чего-то начинать)

D>Всегда! грузит продукты, даже если они вам не нужны. Пожалейте SQL Server. Также оно автоматически трекает изменения этих обьектов.


думаю, что это потому, что игрушечный проект. и, повторюсь, что книга не про EF.


ссылка на проект
Re[3]: EF вопрос
От: Danchik Украина  
Дата: 26.06.19 08:20
Оценка: 2 (1) +1 -1
Здравствуйте, Kaifa, Вы писали:

[Skip]

K>думаю, что это потому, что игрушечный проект. и, повторюсь, что книга не про EF.


K>ссылка на проект


Тут надо EF Core гуру. Подозреваю пока ты эту модель сам ручками не задефайнишь нормально, оно не взлетит.
Я потыкался как котенок, постучал бубном — какая-то хрень. Все по докам, получается пшик. И знает что ключ и что Identity — и все равно наровит пихануть данные в базу.

P.S.
Я вам сочувствую EF Core, это поделка для Hello World сайтов.
Re[4]: EF вопрос
От: Kaifa Россия  
Дата: 26.06.19 08:52
Оценка: +1
D>P.S.
D>Я вам сочувствую EF Core, это поделка для Hello World сайтов.

а какие альтернативы? hibernate? по тому что на хх видел, еф — штука популярная...
Re[5]: EF вопрос
От: fmiracle  
Дата: 26.06.19 09:37
Оценка: +3
Здравствуйте, Kaifa, Вы писали:

D>>Я вам сочувствую EF Core, это поделка для Hello World сайтов.

K>а какие альтернативы? hibernate? по тому что на хх видел, еф — штука популярная...

С linq2db работать исключительно приятно. Но EF более распространенный и популярный, да.
Re: EF вопрос
От: ksg71 Германия  
Дата: 26.06.19 11:04
Оценка:
Здравствуйте, Kaifa, Вы писали:

K>разбираю пример из книжки



K>нафига?


раньше (до EF Core) KeyAttribute сам делал столбец identity и DatabaseGenerated не нужно было указывать
попробуй убери DatabaseGenerated, тб что он нужен для НЕключевых столбцов

You can mark the non-key (non-id) properties as DB-generated properties by using the DatabaseGeneratedOption.Identity option.
This specifies that the value of the property will be generated by the database on the INSERT statement.
This Identity property cannot be updated.

Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[6]: EF вопрос
От: Max Mustermann  
Дата: 28.06.19 14:16
Оценка: -4
Здравствуйте, fmiracle, Вы писали:

D>>>Я вам сочувствую EF Core, это поделка для Hello World сайтов.

K>>а какие альтернативы? hibernate? по тому что на хх видел, еф — штука популярная...

F>С linq2db работать исключительно приятно.

Тогда уже Dapper cразу, чего мелочиться.

Вопрос правда был про альтернатывы, а не про то, что приятнее.
EF/(n)Hibernate заточены под вполне конкретные сценарии и паттерны, которые linq2db/Dapper/PetaPoco/ просто не поддерживают.
Зато "исключительно приятно", ага.
Re: EF вопрос
От: vorona  
Дата: 02.07.19 10:15
Оценка:
Здравствуйте, Kaifa, Вы писали:

Нужно пометить значение свойства как временное

Пример
Re[2]: EF вопрос
От: Danchik Украина  
Дата: 02.07.19 18:50
Оценка:
Здравствуйте, vorona, Вы писали:

V>Здравствуйте, Kaifa, Вы писали:


V>Нужно пометить значение свойства как временное


V>Пример


Извини, но выглядит как хак. Вопрос в том почему он по умолчанию начинает Identity поля при Insert прокидывать. Чуствую что не должен, но как нормально заставить не понял.
Re[7]: EF вопрос
От: Danchik Украина  
Дата: 02.07.19 18:55
Оценка: +1
Здравствуйте, Max Mustermann, Вы писали:

MM>Здравствуйте, fmiracle, Вы писали:


D>>>>Я вам сочувствую EF Core, это поделка для Hello World сайтов.

K>>>а какие альтернативы? hibernate? по тому что на хх видел, еф — штука популярная...

F>>С linq2db работать исключительно приятно.

MM>Тогда уже Dapper cразу, чего мелочиться.

MM>Вопрос правда был про альтернатывы, а не про то, что приятнее.

MM>EF/(n)Hibernate заточены под вполне конкретные сценарии и паттерны, которые linq2db/Dapper/PetaPoco/ просто не поддерживают.
MM>Зато "исключительно приятно", ага.

Ты лучше объясни почему оно так работает, а про паттерны и их последствия я тебе потом объясню.
Re[3]: EF вопрос
От: vorona  
Дата: 02.07.19 20:51
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Извини, но выглядит как хак. Вопрос в том почему он по умолчанию начинает Identity поля при Insert прокидывать. Чуствую что не должен, но как нормально заставить не понял.


В 3.0 поведение изменится
Re[4]: EF вопрос
От: Danchik Украина  
Дата: 02.07.19 22:29
Оценка:
Здравствуйте, vorona, Вы писали:

V>Здравствуйте, Danchik, Вы писали:


D>>Извини, но выглядит как хак. Вопрос в том почему он по умолчанию начинает Identity поля при Insert прокидывать. Чуствую что не должен, но как нормально заставить не понял.


V>В 3.0 поведение изменится


Это я читал, но оно не из той оперы. Оно на заставляет писать Identity поле в базу, просто значение не сторит в самом объекте.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.