Вычисленная колонка в 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?
Ответы
Ответ 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() не является важной частью этого сообщения, вы можете использовать что-нибудь на своем месте, чтобы выполнить необходимую работу. Ура!