C# EntityFramework 6反规范化列以避免频繁联接的最简单方法
让我们假设,我有两个实体C# EntityFramework 6反规范化列以避免频繁联接的最简单方法,c#,entity-framework,C#,Entity Framework,让我们假设,我有两个实体 class Author{ public int Id{get;set;} public string Name{get;set;} //..... } class Article{ public int Id{get;set;} public int AuthorId{get;set;} public string Text{get;set;} } 现在我想在文章AuthorNameproperty中添加现有Autho
class Author{
public int Id{get;set;}
public string Name{get;set;}
//.....
}
class Article{
public int Id{get;set;}
public int AuthorId{get;set;}
public string Text{get;set;}
}
现在我想在文章AuthorName
property中添加现有Author.Name,以简化生成的linq查询和执行时间。我确信我的数据库将只被一个Asp.NETMVC项目使用。使用EF(无数据库触发器)实现此类列的常见方法是什么
这里还有一个更难的例子。假设我想在由文章的文本属性计算的
作者
实体中有TotalWordCountInAllArticles
列。您可以将AuthorName
属性添加到文章
中,并通过确保创建文章
或更新Author.Name
还更新了所有文章
。与TotalWordCount
相同,当文章的时间发生变化时,重新计算其他文章的所有计数
有几种模式可以让这变得更加自动化,比如域事件模式(),但它肯定不仅仅是即插即用。这取决于这些是否只是几个项目,或者这是否会经常发生
如果经常对数据进行非规范化处理以提高性能,您可能希望更多地了解一个体系结构,其中有一个规范化的DB,然后是一个单独的进程,该进程会生成数据的非规范化视图并将其放入文档存储。您可以将AuthorName
属性添加到文章
中,并通过确保创建文章
或更新作者。姓名
也会更新所有文章
。与TotalWordCount
相同,当文章的时间发生变化时,重新计算其他文章的所有计数
有几种模式可以让这变得更加自动化,比如域事件模式(),但它肯定不仅仅是即插即用。这取决于这些是否只是几个项目,或者这是否会经常发生
如果经常对数据进行非规范化处理以提高性能,您可能希望了解更多的体系结构,其中有一个规范化的DB,然后是一个单独的进程,该进程生成数据的非规范化视图并放入文档存储。注意:这可能无法回答您问题的EF部分,但它确实为您的问题提供了另一种解决方案
不确定你在开发项目的过程中有多远,但你可能想考虑一下让它变得琐碎、快速,并提供一些其他的好处。
让我们假设对您的文章模型进行了一个小的更改,以包括作者模型
public class Article
{
public int ArticleId { get; set; }
public string Text { get; set; }
// using Author model
public Author Author { get; set; }
}
假设您希望执行的SQL在概念上类似于:
select article.[Id]
,article.[Text]
,article.[AuthorId]
,author.Name
from [Article] article
join [Author] author on author.AuthorId = article.AuthorId;
使用Drapper实现一个存储库来检索它们将非常简单。它可能看起来像:
public class ArticleRepository : IArticleRepository
{
// IDbCommander is a Drapper construct
private readonly IDbCommander _commander;
/// <summary>
/// Initializes a new instance of the <see cref="ArticleRepository"/> class,
/// injecting an instance of the IDbCommander using your IoC framework of
/// choice.
/// </summary>
public ArticleRepository(IDbCommander commander)
{
_commander = commander;
}
/// <summary>
/// Retrieves all article instances.
/// </summary>
public IEnumerable<Article> RetrieveAll()
{
// pass the query method a reference to a
// mapping function (Func<T1, T2, TResult>)
// although you *could* pass the predicate
// in right here, the code is more readable
// when it's separated out.
return _commander.Query(Map.AuthorToArticle);
}
private static class Map
{
// simple mapping function which allows you
// to map out exactly what you want, exactly
// how you want it. no hoop jumping!
internal static Func<Article, Author, Article>
AuthorToArticle = (article, author) =>
{
article.Author = author;
return article;
};
}
}
公共类ArticleRepository:IArticleRepository
{
//IDbCommander是一个Drapper构造
私人只读IDBcommanderu commander;
///
///初始化类的新实例,
///使用IoC的框架注入IDbCommander的实例
///选择。
///
公共物品储存库(IDB指挥官)
{
_指挥官=指挥官;
}
///
///检索所有项目实例。
///
公共数字
你为什么要考虑这个问题?
走这条路线有很多好处:
- 您指出了性能问题(执行时间)。Drapper是构建在Dapper之上的抽象层,Dapper是高性能micro ORM之王
- 您可以显式地控制对象的映射-没有奇怪的语义或框架怪癖(就像您面临的那个)
- 没有自动生成的SQL。您可以决定将执行什么样的SQL
- SQL与C#分离-如果模式发生更改(可能是为了提高性能),则无需重新编译项目、更改实体映射或更改任何域代码或存储库逻辑。只需在配置中更新SQL代码即可
- 同样,您可以将服务/存储库层设计为更加领域友好,而不必担心数据访问问题会污染服务层(反之亦然)
- 完全可测试-您可以轻松模拟IDB命令的结果
- 更少的编码—不需要实体和dto(除非您需要),不需要重写模型创建方法或从DbContext派生的方法,也不需要POCO上的特殊属性
这只是冰山一角。注意:这可能无法回答您问题的EF部分,但它确实为您的问题提供了另一种解决方案
不确定你在开发项目的过程中有多远,但你可能想考虑一下让它变得琐碎、快速,并提供一些其他的好处。
让我们假设对您的文章模型进行了一个小的更改,以包括作者模型
public class Article
{
public int ArticleId { get; set; }
public string Text { get; set; }
// using Author model
public Author Author { get; set; }
}
假设您希望执行的SQL在概念上类似于:
select article.[Id]
,article.[Text]
,article.[AuthorId]
,author.Name
from [Article] article
join [Author] author on author.AuthorId = article.AuthorId;
使用Drapper实现一个存储库来检索它们将非常简单。它可能看起来像:
public class ArticleRepository : IArticleRepository
{
// IDbCommander is a Drapper construct
private readonly IDbCommander _commander;
/// <summary>
/// Initializes a new instance of the <see cref="ArticleRepository"/> class,
/// injecting an instance of the IDbCommander using your IoC framework of
/// choice.
/// </summary>
public ArticleRepository(IDbCommander commander)
{
_commander = commander;
}
/// <summary>
/// Retrieves all article instances.
/// </summary>
public IEnumerable<Article> RetrieveAll()
{
// pass the query method a reference to a
// mapping function (Func<T1, T2, TResult>)
// although you *could* pass the predicate
// in right here, the code is more readable
// when it's separated out.
return _commander.Query(Map.AuthorToArticle);
}
private static class Map
{
// simple mapping function which allows you
// to map out exactly what you want, exactly
// how you want it. no hoop jumping!
internal static Func<Article, Author, Article>
AuthorToArticle = (article, author) =>
{
article.Author = author;
return article;
};
}
}
公共类ArticleRepository:IArticleRepository
{
//IDbCommander是一个Drapper构造
私人只读IDBcommanderu commander;
///
///初始化类的新实例,
///使用IoC的框架注入IDbCommander的实例
///选择。
///
公共物品储存库(IDB指挥官)
{
_指挥官=指挥官;
}
///
///