سری بررسی SQL Smell در EF Core - استفاده از مدل Entity Attribute Value - بخش اول
نویسنده: سیروان عفیفی
تاریخ: ۱۳۹۹/۰۵/۱۲ ۲۰:۵۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
create table Employees ( Id int auto_increment primary key, FirstName text null, LastName text null, DateOfBirth timestamp not null );
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTimeOffset DateOfBirth { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseMySQL(_configuration.GetConnectionString("DataConnection"));
}
}
اما در مدل EAV، خواص داینامیک را به درون جدول دومی منتقل خواهیم کرد:
create table EmployeeEav ( Id int auto_increment primary key ); create table EmployeeAttributes ( Id int auto_increment primary key, EmployeeId int not null, AttributeName text null, AttributeValue text null, constraint FK_EmployeeAttributes_EmployeeEav_EmployeeId foreign key (EmployeeId) references EmployeeEav (Id) on delete cascade ); create index IX_EmployeeAttributes_EmployeeId on EmployeeAttributes (EmployeeId);
تعریف جداول فوق نیز در Entity Framework به اینصورت خواهند بود:
public class EmployeeEav
{
public int Id { get; set; }
public virtual ICollection<EmployeeAttribute> Attributes { get; set; }
}
public class EmployeeAttribute
{
public int Id { get; set; }
public virtual EmployeeEav Employee { get; set; }
public int EmployeeId { get; set; }
public string AttributeName { get; set; }
public string AttributeValue { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<EmployeeEav> EmployeeEav { get; set; }
public DbSet<EmployeeAttribute> EmployeeAttributes { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseMySQL(_configuration.GetConnectionString("DataConnection"));
}
}
SELECT `e`.`Id`, `e`.`DateOfBirth`, `e`.`FirstName`, `e`.`LastName` FROM `Employees` AS `e` WHERE `e`.`DateOfBirth` > @__endDate_0
var endDate = DateTimeOffset.Now.AddYears(Convert.ToInt32(-25)); var normalTypes = dbContext.Employees.Where(x => x.DateOfBirth > endDate).ToList();
SELECT MAX(CASE AttributeName
WHEN 'FirstName'
THEN AttributeValue
END) AS FirstName,
MAX(CASE AttributeName
WHEN 'LastName'
THEN AttributeValue
END) AS LastName,
MAX(CASE AttributeName
WHEN 'DateOfBirth'
THEN AttributeValue
END) AS DateOfBirth
FROM efcoresample.EmployeeAttributes
WHERE EmployeeId IN (SELECT EmployeeId
FROM efcoresample.EmployeeAttributes
WHERE AttributeName = 'DateOfBirth'
AND AttributeValue > DATE_SUB(CURRENT_DATE(), INTERVAL 25 YEAR))
AND AttributeName IN ('FirstName', 'LastName', 'DateOfBirth')
GROUP BY EmployeeId; string[] columnNames = {"FirstName", "LastName", "DateOfBirth"};
var employees = dbContext.EmployeeAttributes
.Where(x =>
dbContext.EmployeeAttributes
.Where(i => i.AttributeName == "DateOfBirth")
.Select(eId => eId.EmployeeId).Contains(x.EmployeeId) &&
columnNames.Contains(x.AttributeName))
.GroupBy(x => x.EmployeeId)
.Select(g => new
{
FirstName = g.Max(f => f.AttributeName == "FirstName" ? f.AttributeValue : ""),
LastName = g.Max(f => f.AttributeName == "LastName"? f.AttributeValue : ""),
DateOfBirth = g.Max(f => f.AttributeName == "DateOfBirth"? f.AttributeValue : ""),
Id = g.Key
})
.ToList()
.Where(x => DateTime.ParseExact(x.DateOfBirth, "yyyy-MM-dd", CultureInfo.InvariantCulture) > DateTime.Now.AddYears(-25));