当前位置:  编程技术>.net/c#/asp.net
本页文章导读:
    ▪Entity Framework Code First 学习日记(7)-多对多关系      上一次的日记中我们详细讨论了Entity Framework Code First如何建立表之间的一对多关系。这次的日记中我们将详细介绍Entity Framework Code First建立多对多关系的默认行为,以及如何通过Fluent API改变.........
    ▪《Effective C#》读书笔记——条目25:用事件模式实现通知<使用C#表达设计>        .NET中的事件其实就是一个观察者模式(Observer Pattern)的一个语法上的快捷实现(更多可以参考:使用委托和事件实现观察者模式)。事件是一种内建的委托,用来为事件处理函数提供类型安全.........
    ▪asp.net 中 Eval() Bind() <%%> <%=%> 总结      eval和bind都是绑定datatable或者其他(集合,等)中的内容,那么他们有什么区别呢?性能方面怎么样呢?eval有哪几种用法呢?本文将做详细介绍:ASP.NET中的Eval和DataBinder.Eval方法bind是双向绑定.........

[1]Entity Framework Code First 学习日记(7)-多对多关系
    来源:    发布时间: 2013-10-28

上一次的日记中我们详细讨论了Entity Framework Code First如何建立表之间的一对多关系。这次的日记中我们将详细介绍Entity Framework Code First建立多对多关系的默认行为,以及如何通过Fluent API改变默认行为。

本次日记主要介绍一下内容:

1.Entity Framework Code First在什么情况下会建立表之间的多对多关系,以及建立多对多关系时的默认配置。

2.如何通过Fluent API更改Entity Framework Code First建立多对多关系时的默认配置。

 

1.Entity Framework Code First在什么情况下会建立表之间的多对多关系,以及建立多对多关系时的默认配置。

假设我们的业务领域再次发生了改变,客户要求我们记录每种产品的打折信息。根据我们和客户的交谈,我们可以得到如下的业务逻辑:

每个产品种类需要保留所有和它相关的打折促销记录。每次打折促销都有固定的开始时间,结束时间,促销的产品列表以及打折的折扣率。

我们根据这个业务领域的变化重新改写了我们的ProductCatalog类:

 

public class ProductCatalog
{
public int ProductCatalogId { get; set; }
public string CatalogName { get; set; }
public string Manufactory { get; set; }
public decimal ListPrice { get; set; }
public decimal NetPrice { get; set; }
public List<Product> ProductInStock { get; set; }
public List<SalesPromotion> SalesPromotionHistory { get; set; }

public ProductCatalog()
{
SalesPromotionHistory = new List<SalesPromotion>();
ProductInStock = new List<Product>();
}

public Product GetProductInStock()
{
if (ProductInStock.Count <= 0)
{
throw new Exception("No product in stock");
}
Product product = ProductInStock[0];
ProductInStock.RemoveAt(0);
return product;
}

public void PurchaseProduct(List<Product> products)
{
ProductInStock.AddRange(products);
}

public void PurchaseProduct(List<Product> products,decimal newListPrice,decimal newNetPrice)
{
ProductInStock.AddRange(products);
ListPrice = newListPrice;
NetPrice = newNetPrice;
}

public decimal GetPromotionPrice()
{
if (SalesPromotionHistory.Count <= 0)
{
return ListPrice;
}
decimal listPrice = 0;
foreach (var promotion in SalesPromotionHistory)
{
if (promotion.StartDate <= DateTime.Now && promotion.EndDate >= DateTime.Now)
{
listPrice = ListPrice * promotion.SalesDiscount;
}
}
return listPrice;
}
}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

 

我们也根据业务领域定义了我们的SalesPromotion类

public class SalesPromotion
{
public int SalesPromotionId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public decimal SalesDiscount { get; set; }
public List<ProductCatalog> PromotionProductCatalog { get; set; }

public SalesPromotion()
{
PromotionProductCatalog = new List<ProductCatalog>();
}

public void AddProductCatalogToPromotion(ProductCatalog catalog)
{
catalog.SalesPromotionHistory.Add(this);
PromotionProductCatalog.Add(catalog);
}
}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

 

我们可以写一次单元测试方法,测试一下Entity Framework Code First会根据类的定义建立出怎样的数据表关系。

[TestMethod]
public void CanAddSalesPromotion()
{
OrderSystemContext unitOfWork = new OrderSystemContext();
ProductRepository repository = new ProductRepository(unitOfWork);
ProductCatalog catalog = repository.GetProductCatalogById(1);
SalesPromotion promotion = new SalesPromotion { StartDate = DateTime.Parse("2013-1-18"), EndDate = DateTime.Parse("2013-1-25"), SalesDiscount = 0.75M };
promotion.AddProductCatalogToPromotion(catalog);
unitOfWork.CommitChanges();
}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }

 

我们打开数据库看一下,看看Entity Framework Code First从类的定义映射出来的数据库结构是怎样的?

 

大家可以看到由于我们的SalesPromotion和ProductCatalog类中都包含对方类的实例集合,在这种情况下,Entity Framework Code First默认地会将类之间的引用关系映射为数据库表之间的多对多关系。Entity Framework会建立一个多对多的连接表,表的名字是两个关联表的名字加在一起,然后按照它自己的规则去给你加上复数形式。表中的两个字段,既是引用两个关联表的外键,并且也作为这个新的连接表的联合主键。

但是大家可能会发现连接表的名字和连接表中字段的名字都是Entity Framework Code First按照自己的规则定义的,我们可以对它们进行修改。

 

 

2.如何通过Fluent API更改Entity Framework Code First建立多对多关系时的默认配置

我们可以通过上一次日记我们介绍的Has和With方法去配置连接表的名字和连接表中两个外键列的名字。

public class SalesPromotionEntityConfiguration:EntityTypeConfiguration<SalesPromotion>
{
public SalesPromotionEn
    
[2]《Effective C#》读书笔记——条目25:用事件模式实现通知<使用C#表达设计>
    来源:    发布时间: 2013-10-28

  .NET中的事件其实就是一个观察者模式(Observer Pattern)的一个语法上的快捷实现(更多可以参考:使用委托和事件实现观察者模式)。事件是一种内建的委托,用来为事件处理函数提供类型安全的方法签名。事件就是对象将信息告知观察者的方式。

 

1.发布者定义事件

  我们来看一个例子,有一个日志类,将应用程序需要分发的信息发送个各个侦听着,这些侦听者可以是控制域、系统日志、数据库等等,首先定义一个在事件触发中复制传递消息的事件参数类:

1 public class LoggerEventArgs : EventArgs
2 {
3 public string message { get; private set; }
4 public int Priority { get; private set; }
5
6 public LoggerEventArgs(int p, string m)
7 {
8 this.Priority = p;
9 this.message = m;
10 }
11 }

 然后是日志类本身:

1 public class Logger
2 {
3 static Logger()
4 {
5 theOnly = new Logger();
6 }
7
8 private Logger()
9 {
10 }
11
12 private static Logger theOnly = null;
13 public static Logger Singleton
14 {
15 get { return theOnly; }
16 }
17 //定义事件
18 public event EventHandler<LoggerEventArgs> Log;
19 //在这里增加消息和日志
20 public void AddMsg(int priority, string msg)
21 {
22 //这里引用临时变量是一个重要的安全措施,可预防多线程环境中的竞争条件
23 //若是没有引用的副本,客户代码可能会在if判断语句和事件处理函数之间移
24 //除事件处理函数,而复制引用之后即可避免这种情况
25 EventHandler<LoggerEventArgs> l = Log;
26 if (l != null)
27 l(this, new LoggerEventArgs(priority, msg));
28 }
29 }

在这里AddMsg()是触发事件的方法,LoggerEventArgs类中定义了事件的优先级和消息内容,委托则为事件处理函数定义了签名。在Logger类内部,事件自动Log定义了事件处理函数。编译器看到这个字段后会自动创建对应的Add和Remove操作符,编译器生成的代码和下面类似:

1 public class Logger
2 {
3 private EventHandler<LoggerEventArgs> log;
4
5 public event EventHandler<LoggerEventArgs> Log
6 {
7 add { log = log + value; }
8 remove { log = log - value; }
9 }
10 public void AddMsg(int priority, string msg)
11 {
12 EventHandler<LoggerEventArgs> l = log;
13 if (l != null)
14 l(this, new LoggerEventArgs(priority, msg));
15 }
16 }

 

或者我们可以直接查看IL代码:

 

2.侦听者订阅事件

  我们可以把日志信息订阅到标准错误控制台输出:


    
[3]asp.net 中 Eval() Bind() <%%> <%=%> 总结
    来源:    发布时间: 2013-10-28
eval和bind都是绑定datatable或者其他(集合,等)中的内容,那么他们有什么区别呢?性能方面怎么样呢?eval有哪几种用法呢?本文将做详细介绍:
ASP.NET中的Eval和DataBinder.Eval方法bind是双向绑定,但需数据源可更改才能用。ASP.NET 2.0改善了模板中的数据绑定操作,把v1.x中的数据绑定语法DataBinder.Eval(Container.DataItem, fieldname)简化为Eval(fieldname)。Eval方法与DataBinder.Eval一样可以接受一个可选的格式化字符串参数。缩短的Eval语法与DataBinder.Eval的不同点在于,Eval会根据最近的容器对象(例如DataListItem)的DataItem属性来自动地解析字段,而DataBinder.Eval需要使用参数来指定容器。由于这个原因,Eval只能在数据绑定控件的模板中使用,而不能用于Page(页面)层。当然,ASP.NET 2.0页面中仍然支持DataBinder.Eval,你可以在不支持简化的Eval语法的环境中使用它。

用法<%# Bind("Subject") %> //绑定字段
<%# Container.DataItemIndex + 1%> //实现自动编号
<%# Container.ItemIndex %> //Repeater自动编号
<%# DataBinder.Eval(Container.DataItem, "[n]") %>
通常使用的方法(這三個性能最好)
<%# DataBinder.Eval(Container.DataItem, "ColumnName") %>
<%# DataBinder.Eval(Container.DataItem, "ColumnName", null) %>
<%# DataBinder.Eval(Container, "DataItem.ColumnName", null) %>
其他用法
<%# ((DataRowView)Container.DataItem)["ColumnName"] %>
<%# ((DataRowView)Container.DataItem).Row["ColumnName"] %>
<%# ((DataRowView)Container.DataItem)["adtitle"] %>
<%# ((DataRowView)Container.DataItem)[n] %>
<%# ((DbDataRecord)Container.DataItem)[0] %>
<%# (((自定义类型)Container.DataItem)).属性.ToString() %>//如果属性为字符串类型就不用ToString()了

Eval用法
DataBinder.Eval范例
<%# DataBinder.Eval(Container.DataItem, "IntegerValue", "{0:c}") %>
格式化字符串参數是可选的。如果忽略参数,DataBinder.Eval 返回对象类型的值,

//显示两位小数
<%# DataBinder.Eval(Container.DataItem, "UnitPrice", "${0:F2}") %>

格式:
{0:d} 日期只显示年月日
{0:yyyy-mm-dd} 按格式显示年月日
{0:c} 货币样式
<%#Container.DataItem("price","{0:¥#,##0.00}")%>
<%# DataBinder.Eval(Container.DataItem,"Company_Ureg_Date","{0:yyyy-M-d}")%>
Specifier Type      Format    Output (Passed Double 1.42)   Output (Passed Int -12400) 
c   Currency         {0:c}      $1.42      -$12,400 
d   Decimal          {0:d}     System.FormatException   -12400 
e   Scientific       {0:e}     1.420000e+000     -1.240000e+004 
f   Fixed point      {0:f}   1.42     -12400.00 
g   General          {0:g}   1.42      -12400 
n   Number with commas for thousands   {0:n}   1.42      -12,400 
r   Round trippable     {0:r}   1.42      System.FormatException 
x   Hexadecimal     {0:x4}   System.FormatException    cf90 

{0:d} 日期只显示年月日
{0:yyyy-mm-dd} 按格式显示年月日

样式取决于 Web.config 中的设置
{0:c}   或 {0:£0,000.00} 货币样式,标准英国货币样式



显示为£3,000.10

{0:c}   或 string.Format("{0:C}", price); 中国货币样式



显示为 ¥3,000.10

{0:c}   或 string.Format("{0:C}", price); 美国货币样式


Eval(" ")绑定两个字段:

 

 

CommandArgument='<%#Eval("dyid").ToString()+Eval("dyid1").ToString()+… %>'这种形式就行
你把Eval("").ToString()当成一个普通字符串,而'<%# %>'保留就行,你高兴怎么处理就怎么处理,
所有字符串的操作都有效,你还可以用静态函数来处理这些字符串。

<asp:TextBox ID="TextBox5" runat="server"
Text='<%# Eval("RZMJ").ToString()+Eval("LDDW").ToString() %>'></asp:TextBox>区别:绑定表达式
<%# Eval("字段名") %>
<%# Bind("字段名") %>
区别 eval是只读数据,Bind是可更新的.(可以读取和写入)对于程序员来说最根本的区别是:
1.Bind是可更新的,是Bind绑定列可编辑,并且可以和数据源控件交互,直接和数据库交互,但是用Bind的话,程序端的自定义操作就不能用了,比如Convert,ToString()等,或自己写的函数,在程序端都不可以
2.eval是只读数据,用eval的话不可以和数据源控件交互,是单向的,但是可以自定义操作
比如上面的<%# Eval("字段名").ToString().Trim()%>
本人从来和数据库交互自己写代码,所以对我来说操作的Eval更方便,基本不用Bind,而且以前写过,绑定泛型的时候
Bind都不支持嵌套类

下面接受啊<%%> <%= %><% %> 放在 HTML中写后台程序代码.
<%= %> 放在HTML中输出一个变量,表达式。。

本文链接


    
最新技术文章:
▪C#通过IComparable实现ListT.sort()排序
▪C#实现对Json字符串处理实例
▪Winform实现抓取web页面内容的方法
▪Winform实现将网页生成图片的方法
▪C#控制台程序中处理2个关闭事件的代码实例
▪WinForm实现同时让两个窗体有激活效果的特效...
▪WinForm实现拦截窗体上各个部位的点击特效实...
▪用C#的params关键字实现方法形参个数可变示例
▪C#判断某程序是否运行的方法
▪C#验证码识别基础方法实例分析
▪C#通过WIN32 API实现嵌入程序窗体
▪C#实现获取鼠标句柄的方法
▪C#事件处理和委托event delegate实例简述
▪C#获取程序文件相关信息的方法
▪C#中的除法运算符与VB.NET中的除法运算符
▪ASP.NET MVC 5使用X.PagedList.Mvc进行分页教程(PagedLi...
docker中文入门学习手册 iis7站长之家
▪C#实现的优酷真实视频地址解析功能(2014新算...
▪C#和SQL实现的字符串相似度计算代码分享
▪C#使用Word中的内置对话框实例
▪C#反射之基础应用实例总结
▪C#生成单页静态页简单实例
▪C#实现SMTP邮件发送程序实例
▪C#实现随鼠标移动窗体实例
▪C#使用GDI+创建缩略图实例
▪C#实现通过模板自动创建Word文档的方法
▪C#中Response.Write常见问题汇总
▪C#中多态、重载、重写区别分析
▪WinFrom中label背景透明的实现方法
▪C#中out保留字用法实例分析
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3