Подтвердить что ты не робот

Вычисленная колонка в EF Code First

Мне нужно иметь один столбец в моей базе данных, рассчитанный по базе данных как (сумма строк) - (сумма строкb). Я использую модель кода для создания моей базы данных.

Вот что я имею в виду:

public class Income {
      [Key]
      public int UserID { get; set; }
      public double inSum { get; set; }
}

public class Outcome {
      [Key]
      public int UserID { get; set; }
      public double outSum { get; set; }
}

public class FirstTable {
      [Key]
      public int UserID { get; set; }
      public double Sum { get; set; } 
      // This needs to be calculated by DB as 
      // ( Select sum(inSum) FROM Income WHERE UserID = this.UserID) 
      // - (Select sum(outSum) FROM Outcome WHERE UserID = this.UserID)
}

Как я могу добиться этого в EF CodeFirst?

4b9b3361

Ответ 1

Вы можете создать вычисленные столбцы в ваших таблицах базы данных. В модели EF вы просто комментируете соответствующие свойства атрибутом DatabaseGenerated:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public double Summ { get; private set; } 

Или с плавным отображением:

modelBuilder.Entity<Income>().Property(t => t.Summ)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)

Как было предложено Matija Grcic, и в комментарии, это хорошая идея сделать свойство private set, потому что вы, вероятно, никогда не захотите его установить код приложения. У Entity Framework нет проблем с частными сеттерами.

Ответ 2

public string ChargePointText { get; set; }

public class FirstTable 
{
    [Key]
    public int UserID { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]      
    public string Summ 
    {
        get { return /* do your sum here */ }
        private set { /* needed for EF */ }
    }
}

Ссылки:

Ответ 3

Один способ делает это с LINQ:

var userID = 1; // your ID
var income = dataContext.Income.First(i => i.UserID == userID);
var outcome = dataContext.Outcome.First(o => o.UserID == userID);
var summ = income.inSumm - outcome.outSumm;

Вы можете сделать это в своем объекте POCO public class FirstTable, но я бы не предложил, потому что Я думаю, это нехороший дизайн.

Другой способ - использовать представление SQL. Вы можете прочитать представление, подобное таблице с Entity Framework. И внутри кода представления вы можете делать расчеты или что угодно. Просто создайте представление, подобное

-- not tested
SELECT FirstTable.UserID, Income.inCome - Outcome.outCome
  FROM FirstTable INNER JOIN Income
           ON FirstTable.UserID = Income.UserID
       INNER JOIN Outcome
           ON FirstTable.UserID = Outcome.UserID

Ответ 4

Я бы об этом подумал, просто используя модель представления. Например, вместо того, чтобы иметь класс FirstTable в качестве объекта db, не лучше ли вам просто иметь класс модели представлений FirstTable, а затем использовать функцию, которая используется для возврата этого класса, который будет включать рассчитанную сумму? Например, ваш класс будет просто:

public class FirstTable {
  public int UserID { get; set; }
  public double Sum { get; set; }
 }

И тогда у вас будет функция, которую вы вызываете, которая возвращает рассчитанную сумму:

public FirsTable GetNetSumByUserID(int UserId)
{
  double income = dbcontext.Income.Where(g => g.UserID == UserId).Select(f => f.inSum);
  double expenses = dbcontext.Outcome.Where(g => g.UserID == UserId).Select(f => f.outSum);
  double sum = (income - expense);
  FirstTable _FirsTable = new FirstTable{ UserID = UserId, Sum = sum};
  return _FirstTable;
}

В основном то же, что и представление SQL, и, как упоминалось в @Linus, я не думаю, что было бы хорошей идеей сохранить вычисленное значение в базе данных. Просто некоторые мысли.

Ответ 5

Я наткнулся на этот вопрос, пытаясь создать модель EF Code First со строковым столбцом "Slug", быть полученным из другого столбца строки "Имя". Подход, который я принял, был немного иным, но хорошо разработан, поэтому я расскажу его здесь.

private string _name;

public string Name
{
    get { return _name; }
    set
    {
        _slug = value.ToUrlSlug(); // the magic happens here
        _name = value; // but don't forget to set your name too!
    }
}

public string Slug { get; private set; }

Что нравится в этом подходе, вы получаете автоматическое создание пули, не подвергая риску сетку. Метод .ToUrlSlug() не является важной частью этого сообщения, вы можете использовать что-нибудь на своем месте, чтобы выполнить необходимую работу. Ура!