one2many отношение, получить родителя с ребенком - PullRequest
0 голосов
/ 25 сентября 2018
public void getForm(string scode) {    
Form result = DBContext.Forms.Where(f => f.Code == fCode && f.SCode == sCode).FirstOrDefault();

    result.Products = result.Products.Where(p => p.Deleted== false).ToList(); // commenting this line fix the problem
return result;
}

Как мы можем объединить две строки выше, чтобы избежать ошибки ниже.

Операция не выполнена: отношение не может быть изменено, так как одно или несколько свойств внешнего ключа не могут иметь значение NULL.Когда в отношение вносится изменение, для соответствующего свойства внешнего ключа устанавливается нулевое значение.Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, свойству внешнего ключа должно быть присвоено другое ненулевое значение или несвязанный объект должен быть удален.

Обновление:

При вызове в другой функции она выдает ошибку выше

public void savetrans(string fcode)
{
                    Form form = GetForm(fCode);
                    var transDb = new DbContext.Data.Transaction()
                    {
                        FId = form.FId,
                        field1= "test",
                        field2= "test",
                        field3= "test",
                    };

                    DbContext.Transactions.Add(transactionDb);

                    DbContext.SaveChanges();
}

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Очевидно ваша база данных имеет Forms и Products.Существует отношение «один ко многим» между Forms и Products: каждый Form имеет ноль или более Products, каждый Product принадлежит ровно одному Form с использованием внешнего ключа (вероятно, Product.FormId)

Ваш первый оператор выбирает один из ваших Forms, который соответствует определенным требованиям, или ноль, если таких Form нет.Не проверяя возвращаемое значение null, вы пытаетесь изменить Products этого Form.

Проблема в том, что может быть несколько Products, которые имеют ненулевой внешний ключ для этого Form.Они являются элементами в ICollection Products формы.Если вы присваиваете новую коллекцию ICollection для Form.Products, структура сущностей хочет установить внешний ключ Products, который был в Form.Products, равным нулю, указывая, что этот продукт больше не принадлежит ни к какой форме.Но в описании вашей модели вы определили, что каждый Product должен принадлежать ровно одному Form.Отсюда и ошибка.

То, что вы должны сделать, зависит от того, что вы хотите от вашей процедуры.Если вы хотите Получить форму с ее не удаленными продуктами , тогда вам следует выполнить запрос.Если вы хотите удалить все удаленные продукты из этих форм из базы данных , вам следует выполнить обновление

Запросить определенную форму с ее не удаленными продуктами

public ICollection<Form> GetFormWithNonDeletedProducts(string scode)
{
    using (var dbContext = new MyDbContext(...))
    {
        return dBContext.Forms                      // from the collection of all Forms
            .Where(form => form.Code == fCode      
                    && form.SCode == sCode)         // keep only the ones that I want
            .Select(form => new Form()              // and create a new Form object
            {                                       // with the properties I plan to use
                 Id = form.Id,
                 Name = form.Name,
                 ...
                 Products = form.Products           // Fetch only the non-deleted products
                     .Where(product => !product.Deleted)
                     .ToList(),
            }
            .FirstOrDefault();
        }
    }
}

Единственная причина, по которой мне нужно создать новый объект Product, заключается в том, что я хочу поместить его в возвращаемое значение.Если вам не нужно возвращаемое значение, вы можете поместить свои извлеченные свойства в анонимный объект.Обычно это более эффективно, потому что вы не будете получать данные, которые не будете использовать из базы данных.

Например, в приведенном выше примере будет назначено Product.FormId.Вам это не понадобится, потому что вы знаете, что все тысячи Продуктов этой Формы будут иметь одинаковое значение FormId: а именно значение Form.Id.

Тот же запрос без извлечения свойств, которые вы не используете (анонимные типы)

using (var dbContext = new MyDbContext(...))
{
    return dBContext.Forms                  // from the collection of all Forms
        .Where(form => form.Code == fCode      
            && form.SCode == sCode)         // keep only the ones that I want
        .Select(form => new                 // and create a new Form object
        {                                   // with the properties I plan to use
                 Id = form.Id,
                 Name = form.Name,
                 ...
                 Products = form.Products   // Fetch only the non-deleted products
                     .Where(product => !product.Deleted)
                     .Select(product => new
                      {                     // Select only properties you plan to use
                          Name = product.Name,
                          Price = product.Price,

                          // not meaningful: you already know the value:
                          // FormId = product.FormId,
                      })
                     .ToList(),
        }
        .FirstOrDefault();
}

Обновите базу данных: удалите удаленные продукты в форме

Хотя ваша функция называется GetForms, кажется, вы хотите использовать ее для удаления удаленных продуктов.

Самый простой способ - использовать DbSet<Products>.RemoveRange:

using (var dbContext = new MyDbContext(...))
{
    // remove all Deleted products of the form with Code equal to fCode
    // and SCode equal to sCode
    var productsToDelete = dbContext.Products
        .Where(product => product.Deleted
            && product.Form.Code == fCode
            && product.Form.Scode == sCode);
    // note: query is not executed yet!

    dbContext.Products.RemoveRange(productsToDelete);
    dbContext.SaveChanges();
}

Возможно, вам придется сделать RemoveRange(productsToDelete.ToList()), вам придется проверить это.

0 голосов
/ 25 сентября 2018

Если вы хотите удалить продукты, помеченные как удаленные:

var deletedProducts = result.Products.Where(x => x.Deleted).ToList();
foreach(var deletedProduct in deletedProducts)
  result.Products.Remove(deletedProduct);

Если Form.Products имеет значение List<Product>, тогда вы можете использовать .RemoveAll(x => x.Deleted)

Если вы просто хотитечтобы исключить удаленные продукты при работе с вашей организацией, я бы порекомендовал использовать для этой цели несопоставленное свойство:

public class Form
{
   public ICollection<Product> Products { get; set; } = new List<Product>();

   [NotMapped]
   public IReadOnlyCollection<Product> ActiveProducts => Products.Where(x => !x.Deleted).ToList().AsReadOnly();
   // or
   public IReadOnlyCollection<Product> ActiveProducts
   {
     get { return Products.Where(x => !x.Deleted).ToList().AsReadOnly();
   }
}

Тогда, когда вы хотите использовать только активные продукты, используйте .ActiveProducts.Предостережение в этом подходе заключается в том, что вы не можете использовать это свойство в выражениях EF Linq, и его следует использовать только для чтения.Например, не пытайтесь что-то вроде:

var products = context.Forms.Where(x => x.FormId == formId).SelectMany(x => x.ActiveProducts);

Это приведет к ошибке, потому что EF не будет отображать ActiveProducts.Вам придется использовать .Products с соответствующим фильтром для Deleted.

Обычно я использую логику, например, активную / неактивную при заполнении моделей представления, а не на уровне объекта.Объекты должны отражать модель данных, а бизнес-логика, которая применяется к тому, как вы просматриваете / взаимодействуете с этой логикой, представлена ​​вашими моделями представления.Преимущество использования модели представления заключается в том, что проверка состояния «Активно / Удалено» выполняется один раз, когда модели представления заполнены, и они не отравляют сущность свойствами, которые недопустимы в некоторых случаях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...