<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_Ido</title><subtitle type="text">我的博客</subtitle><id>http://feed.cnblogs.com/blog/u/64291/rss</id><updated>2012-05-08T09:22:05Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/64291/rss"/><entry><id>http://www.cnblogs.com/hyl8218/archive/2012/05/08/2490417.html</id><title type="text">iirf有时有效，有时返回404错误的解决方法</title><summary type="text">RewriteFilterPriority HIGH添加到IirfGlobal.ini。</summary><published>2012-05-08T09:22:00Z</published><updated>2012-05-08T09:22:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2012/05/08/2490417.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2012/05/08/2490417.html"/><content type="html">&lt;p&gt;RewriteFilterPriority HIGH&lt;/p&gt;&lt;p&gt;添加到IirfGlobal.ini。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2490417.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2012/05/08/2490417.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2012/04/20/2459442.html</id><title type="text">lucene---GROUP BY、DISTINCT</title><summary type="text">写过两篇关于LUCENE高性能GROUP BY、DISTINCT的文章，最近在研究LUCENE的过程中发现了一个名为FieldCache的东东，于是乎重新改进Lucene高性能GROUP BY、DISTINCT，发现性能有了数量级别的提升，究竟是因为啥让它有了如此之高的性能提升呢？下面我就来为大家揭开这个谜团！ FieldCache是啥？ 我们知道，如果对每一个文档号都用reader 读取域的值会影响速度，所以Lucene 引入了FieldCache 来进行缓存，而FieldCache 并非在存储域中读取，而是在索引域中读取，从而 不必构造Document 对象，然而要求此索引域是不分词的，有</summary><published>2012-04-20T07:57:00Z</published><updated>2012-04-20T07:57:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2012/04/20/2459442.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2012/04/20/2459442.html"/><content type="html">&lt;div class="blog_title"&gt;&lt;div class="news_tag"&gt;写过两篇关于LUCENE高性能GROUP BY、DISTINCT的文章，最近在研究LUCENE的过程中发现了一个名为FieldCache的东东，于是乎重新改进Lucene高性能GROUP BY、DISTINCT，发现性能有了数量级别的提升，究竟是因为啥让它有了如此之高的性能提升呢？下面我就来为大家揭开这个谜团！ &lt;br /&gt;&lt;br /&gt;FieldCache是啥？ &lt;br /&gt;&lt;br /&gt;我们知道，如果对每一个文档号都用reader 读取域的值会影响速度，所以Lucene 引入了FieldCache 来进行缓存，而FieldCache 并非在存储域中读取，而是在索引域中读取，从而 &lt;br /&gt;不必构造Document 对象，然而要求此索引域是不分词的，有且只有一个Token。 &lt;br /&gt;&lt;br /&gt;讲到这里，我们似乎知道了一些东西，那就是，索引进LUCENE中数据至少会在两个地方有相关的存储，一个就是存储域，一个就是索引域。 &lt;br /&gt;&lt;br /&gt;即然FieldCache说它是从索引域中读取，速度相对从存储域读取肯定快，为什么不用它呢？ &lt;br /&gt;&lt;br /&gt;说干就干，经过一番折腾，得到下面的测试结果： &lt;br /&gt;&lt;br /&gt;环境：对100W条数据量，取出其中要分组的字段，当然这个字段是不分词索引进去的 &lt;br /&gt;&lt;br /&gt;第一种方式：从Term区域读取 &lt;br /&gt;View Code &lt;br /&gt;&lt;br /&gt;Dictionary&amp;lt;int, object&amp;gt; dictionary = new Dictionary&amp;lt;int, object&amp;gt;(); &lt;br /&gt;Term startTerm = new Term("CompanyID"); &lt;br /&gt;TermEnum te = indexReader.Terms(startTerm); &lt;br /&gt;if (te != null) &lt;br /&gt;{ &lt;br /&gt;Term currTerm = te.Term(); &lt;br /&gt;&lt;br /&gt;while ((currTerm != null) &amp;amp;&amp;amp; (currTerm.Field() == startTerm.Field())) //term fieldnames are interned &lt;br /&gt;{ &lt;br /&gt;//if (te.DocFreq() &amp;gt; 1) &lt;br /&gt;//{ &lt;br /&gt;TermDocs td = indexReader.TermDocs(currTerm); &lt;br /&gt;while (td.Next()) &lt;br /&gt;{ &lt;br /&gt;dictionary.Add(td.Doc(), currTerm.Text()); &lt;br /&gt;} &lt;br /&gt;//} &lt;br /&gt;if (!te.Next()) &lt;br /&gt;{ &lt;br /&gt;break; &lt;br /&gt;} &lt;br /&gt;currTerm = te.Term(); &lt;br /&gt;} &lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;取出100W个CompanyID耗时：共耗时20.9291356秒 &lt;br /&gt;&lt;br /&gt;第二种方式：从FieldCache中读取 &lt;br /&gt;View Code &lt;br /&gt;&lt;br /&gt;StringIndex stringIndex = FieldCache_Fields.DEFAULT.GetStringIndex(indexReader, "CompanyID"); &lt;br /&gt;&lt;br /&gt;取出100W个CompanyID耗时：共耗时2.8249935秒 &lt;br /&gt;&lt;br /&gt;补充：StringIndex有两个属性：lookup、order &lt;br /&gt;&lt;br /&gt;string[] lookup：按照字典顺序排列的所有term &lt;br /&gt;&lt;br /&gt;int[] order：&amp;nbsp; 其中位置表中文档号，order[i]表示第i个document某个field包含的term在lookup中的位置 &lt;br /&gt;&lt;br /&gt;获取docid对应的term的值：termValue = lookup[order[doc]] &lt;br /&gt;&lt;br /&gt;两者性能一目了然，我也不多说了，快去试试吧！ &lt;br /&gt;&lt;br /&gt;最后当然也不忘了说一句，如果你的数据量是千万级别或上亿了，那你必须得考虑分布式计算、并行计算这一类的计术了，呵呵。 &lt;br /&gt;&lt;br /&gt;[by:http://www.cnblogs.com/zengen/archive/2011/04/19/2020681.html] &lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2459442.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2012/04/20/2459442.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2012/04/12/2443316.html</id><title type="text">使用Entity Framework时动态生成lamda表达式</title><summary type="text">public Expression&lt;Func&lt;Job, bool&gt;&gt; ToLambda() { Type type = typeof (Job); ParameterExpression parameterExpression = Expression.Parameter(type, "job"); Expression body = Expression.Equal(Expression.Property(parameterExpression, "MemberId"), Expression.Constant(MemberId</summary><published>2012-04-12T00:52:00Z</published><updated>2012-04-12T00:52:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2012/04/12/2443316.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2012/04/12/2443316.html"/><content type="html">&lt;p&gt;public Expression&amp;lt;Func&amp;lt;Job, bool&amp;gt;&amp;gt; ToLambda()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Type type = typeof (Job);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ParameterExpression parameterExpression = Expression.Parameter(type, "job");&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Expression body = Expression.Equal(Expression.Property(parameterExpression, "MemberId"), Expression.Constant(MemberId));&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Key.IsNotNullAndWhiteSpace())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MemberExpression keyMember = Expression.Property(parameterExpression, "JobName");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Expression value = Expression.Constant(Key);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MethodCallExpression keyExpression = Expression.Call(keyMember,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; typeof (string).GetMethod("Contains"),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; value);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; body = Expression.And(body, keyExpression);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(IsOpen.HasValue)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MemberExpression isOpenExpression = Expression.Property(parameterExpression, "IsOpen");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Expression openExpression = Expression.Equal(isOpenExpression, Expression.Constant(IsOpen));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; body = Expression.And(body, openExpression);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return Expression.Lambda&amp;lt;Func&amp;lt;Job, bool&amp;gt;&amp;gt;(body, parameterExpression);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2443316.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2012/04/12/2443316.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2012/03/26/2417471.html</id><title type="text">使用IKVM在.Net环境下使用Tika</title><summary type="text">原文地址：http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/07/02/using-the-tika-java-library-in-your-net-application-with-ikvm?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed:+KevinMiller+(Kevin+Miller)Using the Tika Java Library In Your .Net Application With IKVMThis may sound </summary><published>2012-03-26T02:23:00Z</published><updated>2012-03-26T02:23:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2012/03/26/2417471.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2012/03/26/2417471.html"/><content type="html">&lt;p&gt;原文地址：&lt;a href="http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/07/02/using-the-tika-java-library-in-your-net-application-with-ikvm?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+KevinMiller+(Kevin+Miller"&gt;http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/07/02/using-the-tika-java-library-in-your-net-application-with-ikvm?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed:+KevinMiller+(Kevin+Miller&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a title="Using the Tika Java Library In Your .Net Application With IKVM" href="http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/07/02/using-the-tika-java-library-in-your-net-application-with-ikvm"&gt;Using the Tika Java Library In Your .Net Application With IKVM&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;This may sound scary and heretical but did you know it is possible to leverage Java libraries from .Net applications with no TCP sockets or web services getting caught in the crossfire? Let me introduce you to &lt;a href="http://www.ikvm.net/"&gt;IKVM&lt;/a&gt;, which is frankly magic:&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;IKVM.NET is an implementation of Java for &lt;a href="http://www.go-mono.org/"&gt;Mono&lt;/a&gt; and the &lt;a href="http://msdn.microsoft.com/netframework/"&gt;Microsoft .NET Framework&lt;/a&gt;. It includes the following components:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A Java Virtual Machine implemented in .NET&lt;/li&gt;&lt;li&gt;A .NET implementation of the Java class libraries&lt;/li&gt;&lt;li&gt;Tools that enable Java and .NET interoperability&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;Using IKVM we have been able to successfully integrate our Dovetail Seeker search application with the &lt;a href="http://tika.apache.org/"&gt;Tika&lt;/a&gt; text extraction library implemented in Java. With Tika we can easily pull text out of rich documents from &lt;a href="http://tika.apache.org/0.7/formats.html"&gt;many supported formats&lt;/a&gt;. Why Tika?&amp;nbsp; Because there is nothing comparable in the .Net world as Tika.&lt;/p&gt;&lt;p&gt;This post will review how we integrated with Tika. If you like code you can find &lt;a href="http://github.com/KevM/tikaondotnet"&gt;this example&lt;/a&gt; in a repo up on Github.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Compiling a Jar Into An Assembly&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;First thing, we need to get our hands on the latest version of Tika. I downloaded and built the Tika source &lt;a href="http://tika.apache.org/0.7/gettingstarted.html"&gt;using Maven as instructed&lt;/a&gt;. The result of this was a few jar files. The one we are interested in is &lt;strong&gt;tika-app-x.x.jar&lt;/strong&gt; which has everything we need bundled into one useful container.&lt;/p&gt;&lt;p&gt;Next up we need to convert this jar we&amp;rsquo;ve built to a .Net assembly. Do this using &lt;a href="http://sourceforge.net/apps/mediawiki/ikvm/index.php?title=Ikvmc"&gt;ikvmc.exe&lt;/a&gt;.&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;tika\build&amp;gt;ikvmc.exe -target:library tika-app-0.7.jar&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Unfortunately, you will see tons of troublesome looking warnings but the end result is a .Net assembly wrapping the Java jar which you can reference in your projects.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Using Tika From .Net&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;IKVM is pretty transparent. You simply reference the the Tika app assembly and your .Net code is talking to Java types. It is a bit weird at first as you have Java versions of types and .Net versions. Next you&amp;rsquo;ll want to make sure that all the dependent IKVM runtime assemblies are included with your project. Using &lt;a href="http://www.red-gate.com/products/reflector/"&gt;Reflector&lt;/a&gt; I found that the Tika app assembly referenced a lot of IKVM assemblies which do not appear to be used. I had to figure out through trial and error which assemblies where not being touched by the rich document extractions being done. If need be you could simple include all of the referenced IKVM assemblies with your application. Below I have done the work for you and eliminated all references to all the IKVM assemblies which appear to be in play.&lt;/p&gt;&lt;p&gt;&lt;a href="http://blogs.dovetailsoftware.com/blogs/kmiller/image_7780AE42.png"&gt;&lt;img style="display: inline; border-width: 0px;" title="image" src="http://www.dovetailsoftware.com/sites/default/files/MTM1MS1pbWFnZV90aHVtYl8xRTRFQzQ4My5wbmc=.png" alt="image" width="604" height="381" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;16 assemblies down to 5. A much smaller deployment.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Using Tika&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;To do some text extraction we&amp;rsquo;ll ask Tika, very nicely, to parse the files we throw at it. For my purposes this involved having Tika automatically determine how to parse the stream and extract the text and metadata about the document.&lt;/p&gt;&lt;div&gt;&lt;div id="highlighter_603487" class="syntaxhighlighter nogutter  csharp ie"&gt;&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp plain"&gt;TextExtractionResult Extract(&lt;/code&gt;&lt;code class="csharp keyword"&gt;string&lt;/code&gt; &lt;code class="csharp plain"&gt;filePath) &lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;var parser = &lt;/code&gt;&lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;AutoDetectParser(); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;var metadata = &lt;/code&gt;&lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;Metadata(); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;var parseContext = &lt;/code&gt;&lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;ParseContext(); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;java.lang.Class parserClass = parser.GetType(); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number7 index6 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;parseContext.&lt;/code&gt;&lt;code class="csharp keyword"&gt;set&lt;/code&gt;&lt;code class="csharp plain"&gt;(parserClass, parser); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number8 index7 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&lt;/code&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="line number9 index8 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;try&lt;/code&gt;&lt;/div&gt;&lt;div class="line number10 index9 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number11 index10 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;var file = &lt;/code&gt;&lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;File(filePath); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number12 index11 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;var url = file.toURI().toURL(); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number13 index12 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;using&lt;/code&gt; &lt;code class="csharp plain"&gt;(var inputStream = MetadataHelper.getInputStream(url, metadata)) &lt;/code&gt;&lt;/div&gt;&lt;div class="line number14 index13 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number15 index14 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;parser.parse(inputStream, getTransformerHandler(), metadata, parseContext); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number16 index15 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;inputStream.close(); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number17 index16 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;} &lt;/code&gt;&lt;/div&gt;&lt;div class="line number18 index17 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&lt;/code&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="line number19 index18 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;return&lt;/code&gt; &lt;code class="csharp plain"&gt;assembleExtractionResult(_outputWriter.toString(), metadata); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number20 index19 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;} &lt;/code&gt;&lt;/div&gt;&lt;div class="line number21 index20 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;catch&lt;/code&gt; &lt;code class="csharp plain"&gt;(Exception ex) &lt;/code&gt;&lt;/div&gt;&lt;div class="line number22 index21 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number23 index22 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;throw&lt;/code&gt; &lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;ApplicationException(&lt;/code&gt;&lt;code class="csharp string"&gt;"Extraction of text from the file '{0}' failed."&lt;/code&gt;&lt;code class="csharp plain"&gt;.ToFormat(filePath), ex); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number24 index23 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;} &lt;/code&gt;&lt;/div&gt;&lt;div class="line number25 index24 alt2"&gt;&lt;code class="csharp plain"&gt;}&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;One Important Cavet&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Java has a concept called a &lt;strong&gt;ClassLoader&lt;/strong&gt; which has something to do with how Java types are found and loaded. There is probably a better way around this but for some reason if you do not implement a custom ClassLoader and also set an application setting cueing the IKVM runtime about which .Net type to use as the ClassLoader.&lt;/p&gt;&lt;div&gt;&lt;div id="highlighter_137750" class="syntaxhighlighter nogutter  csharp ie"&gt;&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp keyword"&gt;class&lt;/code&gt; &lt;code class="csharp plain"&gt;MySystemClassLoader : ClassLoader &lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp plain"&gt;MySystemClassLoader(ClassLoader parent) &lt;/code&gt;&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;: &lt;/code&gt;&lt;code class="csharp keyword"&gt;base&lt;/code&gt;&lt;code class="csharp plain"&gt;(&lt;/code&gt;&lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;AppDomainAssemblyClassLoader(&lt;/code&gt;&lt;code class="csharp keyword"&gt;typeof&lt;/code&gt;&lt;code class="csharp plain"&gt;(MySystemClassLoader).Assembly)) &lt;/code&gt;&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;} &lt;/code&gt;&lt;/div&gt;&lt;div class="line number7 index6 alt2"&gt;&lt;code class="csharp plain"&gt;}&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here is an example &lt;strong&gt;app.config&lt;/strong&gt; telling IKVM where the ClassLoader is found.&lt;/p&gt;&lt;div&gt;&lt;div id="highlighter_889300" class="syntaxhighlighter nogutter  csharp ie "&gt;&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="csharp plain"&gt;&amp;lt;?xml version=&lt;/code&gt;&lt;code class="csharp string"&gt;"1.0"&lt;/code&gt; &lt;code class="csharp plain"&gt;encoding=&lt;/code&gt;&lt;code class="csharp string"&gt;"utf-8"&lt;/code&gt; &lt;code class="csharp plain"&gt;?&amp;gt; &lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;code class="csharp plain"&gt;&amp;lt;configuration&amp;gt; &lt;/code&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;&amp;lt;appSettings&amp;gt; &lt;/code&gt;&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;&amp;lt;add key=&lt;/code&gt;&lt;code class="csharp string"&gt;"ikvm:java.system.class.loader"&lt;/code&gt; &lt;code class="csharp plain"&gt;value=&lt;/code&gt;&lt;code class="csharp string"&gt;"TikaOnDotNet.MySystemClassLoader, TikaOnDotNet"&lt;/code&gt; &lt;code class="csharp plain"&gt;/&amp;gt; &lt;/code&gt;&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;&amp;lt;/appSettings&amp;gt; &lt;/code&gt;&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;&lt;code class="csharp plain"&gt;&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;This step is very important.&lt;/strong&gt; If IKVM cannot find a class loader, for some horrible reason, Tika will work fine but extract only empty documents with no metadata. The main reason this is troubling is that no exception is raised. For this reason we actually have a validation step in our application ensuring that the app setting is present and that it resolves to a valid type.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Demo&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Here is a test demonstrating an extraction and the result.&lt;/p&gt;&lt;div&gt;&lt;div id="highlighter_685214" class="syntaxhighlighter nogutter  csharp ie "&gt;&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="csharp plain"&gt;[Test] &lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp keyword"&gt;void&lt;/code&gt; &lt;code class="csharp plain"&gt;should_extract_from_pdf() &lt;/code&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;var textExtractionResult = &lt;/code&gt;&lt;code class="csharp keyword"&gt;new&lt;/code&gt; &lt;code class="csharp plain"&gt;TextExtractor().Extract(&lt;/code&gt;&lt;code class="csharp string"&gt;"Tika.pdf"&lt;/code&gt;&lt;code class="csharp plain"&gt;); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;textExtractionResult.Text.ShouldContain(&lt;/code&gt;&lt;code class="csharp string"&gt;"pack of pickled almonds"&lt;/code&gt;&lt;code class="csharp plain"&gt;); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number7 index6 alt2"&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="line number8 index7 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp plain"&gt;Console.WriteLine(textExtractionResult); &lt;/code&gt;&lt;/div&gt;&lt;div class="line number9 index8 alt2"&gt;&lt;code class="csharp plain"&gt;}&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Put simply rich documents like this go in.&lt;/p&gt;&lt;p&gt;&lt;a href="http://blogs.dovetailsoftware.com/blogs/kmiller/image_7E33B7C5.png"&gt;&lt;img style="display: inline; border-width: 0px;" title="Test PDF" src="http://www.dovetailsoftware.com/sites/default/files/MTM1MS1pbWFnZV90aHVtYl83NzE0N0I0RC5wbmc=.png" alt="Test PDF" width="638" height="593" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And a &lt;strong&gt;TextExtractionResult&lt;/strong&gt; comes out:&lt;/p&gt;&lt;div&gt;&lt;div id="highlighter_931964" class="syntaxhighlighter nogutter  csharp ie"&gt;&lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp keyword"&gt;class&lt;/code&gt; &lt;code class="csharp plain"&gt;TextExtractionResult &lt;/code&gt;&lt;/div&gt;&lt;div class="line number2 index1 alt1"&gt;&lt;code class="csharp plain"&gt;{ &lt;/code&gt;&lt;/div&gt;&lt;div class="line number3 index2 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp keyword"&gt;string&lt;/code&gt; &lt;code class="csharp plain"&gt;Text { &lt;/code&gt;&lt;code class="csharp keyword"&gt;get&lt;/code&gt;&lt;code class="csharp plain"&gt;; &lt;/code&gt;&lt;code class="csharp keyword"&gt;set&lt;/code&gt;&lt;code class="csharp plain"&gt;; } &lt;/code&gt;&lt;/div&gt;&lt;div class="line number4 index3 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp keyword"&gt;string&lt;/code&gt; &lt;code class="csharp plain"&gt;ContentType { &lt;/code&gt;&lt;code class="csharp keyword"&gt;get&lt;/code&gt;&lt;code class="csharp plain"&gt;; &lt;/code&gt;&lt;code class="csharp keyword"&gt;set&lt;/code&gt;&lt;code class="csharp plain"&gt;; } &lt;/code&gt;&lt;/div&gt;&lt;div class="line number5 index4 alt2"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp keyword"&gt;public&lt;/code&gt; &lt;code class="csharp plain"&gt;IDictionary&amp;lt;&lt;/code&gt;&lt;code class="csharp keyword"&gt;string&lt;/code&gt;&lt;code class="csharp plain"&gt;, &lt;/code&gt;&lt;code class="csharp keyword"&gt;string&lt;/code&gt;&lt;code class="csharp plain"&gt;&amp;gt; Metadata { &lt;/code&gt;&lt;code class="csharp keyword"&gt;get&lt;/code&gt;&lt;code class="csharp plain"&gt;; &lt;/code&gt;&lt;code class="csharp keyword"&gt;set&lt;/code&gt;&lt;code class="csharp plain"&gt;; }&amp;nbsp; &lt;/code&gt;&lt;/div&gt;&lt;div class="line number6 index5 alt1"&gt;&lt;code class="csharp spaces"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;code class="csharp comments"&gt;//toString() override &lt;/code&gt;&lt;/div&gt;&lt;div class="line number7 index6 alt2"&gt;&lt;code class="csharp plain"&gt;}&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here is the raw output from Tika:&lt;/p&gt;&lt;p&gt;&lt;a href="http://blogs.dovetailsoftware.com/blogs/kmiller/image_6FF53ED5.png"&gt;&lt;img style="display: inline; border-width: 0px;" title="image" src="http://www.dovetailsoftware.com/sites/default/files/MTM1MS1pbWFnZV90aHVtYl82NENCQjQ4Qi5wbmc=.png" alt="image" width="650" height="323" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I hope this helps boost your confidence that you can use Java libraries in your .Net code and I hope my &lt;a href="http://github.com/KevM/tikaondotnet"&gt;example repo&lt;/a&gt; will be of assistance if you need to do some work with Tika on the .Net platform. Enjoy.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2417471.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2012/03/26/2417471.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2012/02/23/2364311.html</id><title type="text">Entity Framework一对多关系或一对一关系删除子对象的方法</title><summary type="text">常见问题：无法更改关系，因为一个或多个外键属性不可以为 null。对关系作出更改后，会将相关的外键属性设置为 null 值。如果外键不支持 null 值，则必须定义新的关系，必须向外键属性分配另一个非 null 值，或必须删除无关的对象。解决方法：例如OrderItem和Product是一对多的关系OrderItem.ProductId是关系的外键你要先删除对product的引用，比如表OrderItem里有一个到Product.Id的外键的话，需要将其设为空值对应。所以在删除之前要将OrderItem.ProductId设置为0或null</summary><published>2012-02-23T02:01:00Z</published><updated>2012-02-23T02:01:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2012/02/23/2364311.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2012/02/23/2364311.html"/><content type="html">&lt;p&gt;常见问题：无法更改关系，因为一个或多个外键属性不可以为 null。对关系作出更改后，会将相关的外键属性设置为 null 值。如果外键不支持 null 值，则必须定义新的关系，必须向外键属性分配另一个非 null 值，或必须删除无关的对象。&lt;/p&gt;&lt;p&gt;解决方法：&lt;/p&gt;&lt;p&gt;例如OrderItem和Product是一对多的关系&lt;/p&gt;&lt;p&gt;OrderItem.ProductId是关系的外键&lt;/p&gt;&lt;p&gt;你要先删除对product的引用，比如表OrderItem里有一个到Product.Id的外键的话，需要将其设为空值对应。所以在删除之前要将OrderItem.ProductId设置为0或null&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2364311.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2012/02/23/2364311.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2012/02/22/ef.html</id><title type="text">entity framework中对关系使用默认规则与配置</title><summary type="text">对关系使用默认规则与配置In Chapter 3, you learned about convention and configuration that affect attributes of properties and the effects that these have on the database. In this chapter, the focus will be on convention and configuration that affects the relationships between classes. This includes how classes </summary><published>2012-02-22T09:20:00Z</published><updated>2012-02-22T09:20:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2012/02/22/ef.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2012/02/22/ef.html"/><content type="html">&lt;p&gt;&lt;strong&gt;对关系使用默认规则与配置&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In Chapter 3, you learned about convention and configuration that affect attributes of properties and the effects that these have on the database. In this chapter, the focus will be on convention and configuration that affects the relationships between classes. This includes how classes relate to one another in memory, as well as the corresponding foreign key constraints in the database. You'll learn about controlling multiplicity, whether or not a relationship is required, and working with cascade deletes. You'll see the conventional behavior and learn how to control the relationships using Data Annotations and the Fluent API.&lt;/p&gt;&lt;p&gt;在第3章，你已经掌握了默认规则与配置对属性以及其在数据库映射的字段的影响。在本章，我们把焦点放在类之间的关系上面。这包括类在内存如何关联，还有数据库中的外键维持等。你将了解控制多重性关系，无论是否是必须的，还将学习级联删除操作。你会看到默认行为以及如何使用Data Annnotations和Fluent API来控制关系。&lt;/p&gt;&lt;p&gt;You'll start seeing more configuration that can be performed with the Fluent API but cannot be done through Data Annotations. Recall, however, that if you really love to apply configuration with attributes, the note in "Mapping to Non-Unicode Database Types" on page 51 points to a blog post that demonstrates how to create attributes to perform configuration that is only available through the Fluent API. You've already seen some of the relationship conventions in action throughout the earlier chapters of this book. You built a Destination class (Example 4-1) that has a Lodgings property which is a List&amp;lt;Lodging&amp;gt;.&lt;/p&gt;&lt;p&gt;你会看到很多只能使用Fluent API而不能使用Data Annotations的情况。上一章我们介绍过"映射到非Unicode数据库类型"就只能在Fluent API中找到。在前几章你已经看到了几个有关默认关系的例子，如代码4-1，就是通过建立类型为List&amp;lt;Lodging&amp;gt;的Lodging属性与炻Destination建立了联系。&lt;/p&gt;&lt;p&gt;Example 4-1. The Destination class with a property that points to the Lodging class&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Destination&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; DestinationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Country { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Description { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;byte&lt;/span&gt;[] Photo { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;Lodging&amp;gt; Lodgings { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;On the other end of the relationship, the Lodging class (Example 4-2) has a Destination property that represents a single Destination instance.&lt;/p&gt;&lt;p&gt;在Lodging类（代码4-2）也有一个Destination属性代表单个Destination实例。&lt;/p&gt;&lt;p&gt;Example 4-2. The Lodging class with its reference back to the Destination class&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Lodging&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LodgingId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Owner { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsResort { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; MilesFromNearestAirport { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Destination Destination { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Code First sees that you have defined both a reference and a collection navigation property, so by convention it will configure this as a one-to-many relationship. Based on this, Code First can also determine that Lodging is the dependent end of the relationship (the end with the foreign key) and Destination is the principal end (the end with the primary key). It therefore knows that the table Lodging maps to will need a foreign key pointing back to the primary key of Destination. You saw this played out in Chapter 2, where it created the Destination_DestinationId foreign key field in the Lodgings table.&lt;/p&gt;&lt;p&gt;Code First观察到您既定义了一个引用又有一个集合导航属性，因此引用默认规则将其配置为一对多关系。基于此，Code First可以确定Lodging（外键）与Destination（主键）具有依赖关系。因此获表Lodging需要要一个外键映射到Destination的主键。在第2章你已经看到，在Lodgings表中确实建立了Destination_DestinationId外键字段。&lt;/p&gt;&lt;p&gt;In the rest of this chapter, you will get an understanding of the full set of conventions that Code First has around relationships and how to override those conventions when they don't align with your intent.&lt;/p&gt;&lt;p&gt;本章将全面解析Code First在处理关系的默认规则以及如何按我们的意图覆写这些规则。&lt;/p&gt;&lt;code&gt;Relationships in Your Application Logic &lt;/code&gt;&lt;code&gt;应用程序逻辑中的关系 &lt;/code&gt;&lt;code&gt;Once Code First has worked out the model and its relationships, Entity Framework will treat those relationships just the same as it does with POCOs that are mapped using an EDMX file. All of the rules you learned about working with POCO objects throughout Programming Entity Framework still apply. For example, if you have a foreign key property and a navigation property, Entity Framework will keep them in sync. If you have bidirectional relationships, Entity Framework will keep them in sync as well. At what point Entity Framework synchronizes the values is determined by whether you are leveraging dynamic proxies. Without the proxies, Entity Framework relies on an implicit or explicit call to DetectChanges. With the proxies, the synchronization happens in response to the property value being changed. Typically you do not need to worry about calling DetectChanges because DbContext will take care of calling it for you when you call any of its methods that rely on things being in sync. The Entity Framework team recommends that you only use dynamic proxies if you find a need to; typically this would be around performance tuning. POCO classes without proxies are usually simpler to interact with, as you don't need to be aware of the additional behaviors and nuances that are associated with proxies. &lt;/code&gt;&lt;code&gt;一旦Code First已经创建了模型与关系，EF框架就会将这些关系视为与使用EDMX文件映射的POCO是类似 的。所有你在使用POCO对象对EF框架编程的方法和规则仍然适用。例如，如何有一个外键属性和一个导航属性关系，EF框架就会保持他们的同步。如果存在双向关系，EF框架也同样会保持他们的同步。EF框架在什么点上同步值取决于您是否在利用动态代理。没有代理，EF框架将会隐式或显示调用DetectChanges。使用代理，同步的响应发生在属性值变更的时候。事实上你不需要关心是否调用DetectChanges因为DbConext将会在你调用任何依赖同步的方法自动调用。EF框架开发团队建议你如果需要只用动态代理；通常这都是围绕着性能调优进行的。没有代理的POCO类通常使交互关系理简化，因为你没必要知道代理相关的附加行为。 &lt;/code&gt;&lt;p&gt;&lt;strong&gt;Working with Multiplicity&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;多重性关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;As you've seen, Code First will create relationships when it sees navigation properties and, optionally, foreign key properties. Details about those navigation properties and foreign keys will help the conventions determine multiplicity of each end. We'll focus on foreign keys a little later in this chapter; for now, let's take a look at relationships where there is no foreign key property defined in your class.&lt;/p&gt;&lt;p&gt;Code First applies a set of rules to work out the multiplicity of each relationship. The rules use the navigation properties you defined in your classes to determine multiplicity. There can either be a pair of navigation properties that point to each other (bidirectional relationship) or a single navigation property (unidirectional relationship):&lt;/p&gt;&lt;p&gt;如前所述，Code First在看到导航属性和可选的外键属性时将创建关系。有关导航属性和外键属性的细节将帮助我们来确定多重关系的每一端。本章对外键将关注更多一点；现在我们来看看在类中没有外键关系的属性、&lt;/p&gt;&lt;p&gt;Code First在处理多重性关系时应用了一系列规则。规则使用导航属性确定多重性关系。即可以是一对导航属性互相指定（双向关系），也可以是单个导航属性（单向关系）。&lt;/p&gt;&lt;p&gt;&amp;bull; If your classes contain a reference and a collection navigation property, Code First assumes a one-to-many relationship.&lt;/p&gt;&lt;p&gt;如果你的类中包含一个引用和一个集合导航属性，Code First视为一对多关系；&lt;/p&gt;&lt;p&gt;&amp;bull; Code First will also assume a one-to-many relationship if your classes include a navigation property on only one side of the relationship (i.e., either the collection or the reference, but not both).&lt;/p&gt;&lt;p&gt;如果你的类中仅在单边包含导航属性（即要么是集合要么是引用，只有一种），Code First也将其视为一对多关系；&lt;/p&gt;&lt;p&gt;&amp;bull; If your classes include two collection properties, Code First will use a many-to-many relationship by default.&lt;/p&gt;&lt;p&gt;如果你的类包含两个集合属性，Code First默认会使用多对多关系；&lt;/p&gt;&lt;p&gt;&amp;bull; If your classes include two reference properties, Code First will assume a one-to-one relationship.&lt;/p&gt;&lt;p&gt;如果你的类包含两个引用属性，Code First会视为一对一关系；&lt;/p&gt;&lt;p&gt;&amp;bull; In the case of one-to-one relationships, you will need to provide some additional information so that Code First knows which entity is the principal and which is the dependent. You'll see this in action a little later on in this chapter, in the "Working with One-to-One Relationships" on page 84 section. If no foreign key property is defined in your classes, Code First will assume the relationship is optional (i.e., the one end of the relationship is actually zero-or-one as opposed to exactly-one).&lt;/p&gt;&lt;p&gt;在一对一关系中，你需要提供附加信息以使Code First获知何为主何为辅。本章后面会在"一对一关系"中提到。如果没有在类中定义外键属性，Code First将设定关系为可选（即一端的关系实际是零对一或恰好相反）。&lt;/p&gt;&lt;p&gt;&amp;bull; In the "Working with Foreign Keys" on page 66 section of this chapter, you will see that when you define a foreign key property in your classes, Code First uses the nullability of that property to determine if the relationship is required or optional.&lt;/p&gt;&lt;p&gt;在本章的"外键"小节，你会看到当在类中定义外键属性，Code First会使用属性的可空性来确定关系是必须的还是可选的。&lt;/p&gt;&lt;p&gt;Looking back at the Lodging to Destination relationship that we just revisited, you can see these rules in action. Having a collection and a reference property meant that Code First assumed it was a one-to-many relationship. We can also see that, by convention, Code First has configured it as an optional relationship. But in our scenario it really doesn't make sense to have a Lodging that doesn't belong to a Destination. So let's take a look at how we can make this a required relationship.&lt;/p&gt;&lt;p&gt;回顾我们刚刚重温的Lodging与destination的关系,你会看到上述规则。由于有集合和引用属性，Code First就将其视为一对多关系。同时也看到，通过默认规则，Code First将经将其配置为可选关系。但是在我们的场景里，确实没有想让一个Lodging(住所)不从属于一个Destination(目的地)。因此我们来看看如何确保这种关系是必须的。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Configuring Multiplicity with Data Annotations&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Data Annotations配置多重关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Most of the multiplicity configuration needs to be done using the Fluent API. But we can use Data Annotations to specify that a relationship is required. This is as simple as placing the Required annotation on the reference property that you want to be required. Modify Lodging by adding the Required annotation to the Destination property (Example 4-3).&lt;/p&gt;&lt;p&gt;大多数多重关系配置都需要使用Fluent API。但是我可以使用Data Annotations来指定一些关系是必须的。只需要简单地将Required标记放在你需要定义为必须项的引用属性上。修改Lodging类的代码将Required特笥放在Destination属性上（代码4-3）：&lt;/p&gt;&lt;p&gt;Example 4-3. Required annotation added to Destination property&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Lodging&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LodgingId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Owner { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsResort { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; MilesFromNearestAirport { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[Required] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Destination Destination { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;If you were to run the application so that the database gets recreated with the change you just made, you would see that the Destination_DestinationId column in the Lodgings table no longer allows null values (Figure 4-1). This is because the relationship is now required.&lt;/p&gt;&lt;p&gt;运行程序，数据库重新创建，你会看到Lodgings表中Destination_DestinationId不再允许空值（图4-1）。这是因为关系现在是必须的。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751248493.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Configuring Multiplicity with the Fluent API&lt;/p&gt;&lt;p&gt;使用Fluent API配置多重性关系&lt;/p&gt;&lt;p&gt;Configuring relationships with the Fluent API can look confusing if you haven't taken the time to understand the fundamental ideas. We'll lead you down the path to enlightenment.&lt;/p&gt;&lt;p&gt;When fixing relationships with Data Annotations, you apply annotations directly to the navigation properties. It's very different with the Fluent API, where you are literally configuring the relationship, not a property. In order to do so, you must first identify the relationship. Sometimes it's enough to mention one end, but most often you need to describe the complete relationship.&lt;/p&gt;&lt;p&gt;如果没有花时间去理解基本原理，使用Fluent API配置关系会让人感到迷惑。我们带你对此作些扩展。&lt;/p&gt;&lt;p&gt;当使用Data Annotations修复关系时，你将特性直接放在了导航属性上。这与Fluent API不同，Fluent API并不直接在属性上配置关系。为了达到目的，必须先确定关系。有时在一端就足够，但更多的需要对全部关系进行描述。&lt;/p&gt;&lt;p&gt;To identify a relationship, you point to its navigation properties. Regardless of which end you begin with, this is the pattern:&lt;/p&gt;&lt;p&gt;为了确定关系，你必须指明导航属性。不管从哪端开始，都要使用这样的代码模板：&lt;/p&gt;&lt;p&gt;Entity.Has[Multiplicity](Property).With[Multiplicity](Property)&lt;/p&gt;&lt;p&gt;The multiplicity can be Optional (a property that can have a single instance or be null),Required (a property that must have a single instance), or Many (a property with a collection of a single type).&lt;/p&gt;&lt;p&gt;多重性关系可以是可选的（一个属性可拥有一个单个实例或没有），必备的（一个属性必须拥有一个单个实例）或很多的（一个属性可以拥有一个集合或一个单个实例）。&lt;/p&gt;&lt;p&gt;The Has methods are as follows:&lt;/p&gt;&lt;p&gt;Has方法包括如下几个：&lt;/p&gt;&lt;p&gt;&amp;bull; HasOptional&lt;/p&gt;&lt;p&gt;&amp;bull; HasRequired&lt;/p&gt;&lt;p&gt;&amp;bull; HasMany&lt;/p&gt;&lt;p&gt;In most cases you will follow the Has method with one of the following With methods:&lt;/p&gt;&lt;p&gt;在多数情况还需要在Has方法后面跟随如下With方法之一：&lt;/p&gt;&lt;p&gt;&amp;bull; WithOptional&lt;/p&gt;&lt;p&gt;&amp;bull; WithRequired&lt;/p&gt;&lt;p&gt;&amp;bull; WithMany&lt;/p&gt;&lt;p&gt;Example 4-4 shows a concrete example using the existing one-to-many relationship between Destination and Lodging. This configuration doesn't really do anything, because it is configuring exactly what Code First detected by convention. Later in this chapter, you will see that this approach is used to identify a relationship so that you can perform further configuration related to foreign keys and cascade delete.&lt;/p&gt;&lt;p&gt;代码4-4显示了一个 使用现有的Destination和Lodging之间的一对多关系的实例。这一配置并非真的做任何事，因为这会被Code First通过默认规则同样进行配置。本章后面会看到识别这种关系然后作进一步的配置，实现外键关系和级联删除功能。&lt;/p&gt;&lt;p&gt;Example 4-4. Specifying an optional one-to-many relationship&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;modelBuilder.Entity&amp;lt;Destination&amp;gt;() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasMany(d =&amp;gt; d.Lodgings) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithOptional(l =&amp;gt; l.Destination); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;This identifies a relationship that Destination Has. It has a Many relationship that is defined by its property, Lodgings. And the Lodgings end of the relationship comes along With a relationship (which is Optional) to Destination. Figure 4-2 attempts to help you visualize this relationship the way the model builder sees it.&lt;/p&gt;&lt;p&gt;这一代码确定Destination的Has关系。有很多由Lodgings定义的关系。Lodgings端到Destination的关系是可选的。图4-2尝试帮你观察这种关系建立的过程。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751255428.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;We looked at how to change this to be a required relationship with Data Annotations,so now let's see how to do the same with the Fluent API. Add the configuration shown in Example 4-6 to your DestinationConfiguration class.&lt;/p&gt;&lt;p&gt;我们来看看如何使用Fluent API建立必须关系。在DestinationConfiguration添加代码4-6：&lt;/p&gt;&lt;p&gt;Example 4-6. Configuring a required relationship with the Fluent API&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;HasMany(d =&amp;gt; d.Lodgings) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithRequired(l =&amp;gt; l.Destination); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;This looks very similar to the configuration we saw in Example 4-5, except, instead of calling HasOptional, you are now calling HasRequired. This lets Code First know that you want this one-to-many relationship to be required rather than optional. Run the application again and you will see that the database looks the same as it did in Figure 4-1 when you used Data Annotations to configure the relationship to be required.&lt;/p&gt;&lt;p&gt;这看起来非常类型于代码4-5，只不过调用了HasRequired。这会使Code First你想建立一个必须的一对多关系。运行程序你会看到数据库与图4-1显示的一样，与使用Data Annotations的Required标记产生效果一致。&lt;/p&gt;&lt;code&gt;If you are configuring a one-to-one relationship where both ends are required or both ends are optional, Code First will need some more information from you to work out which end is the principal and which end is the dependent. This area of the Fluent API can get very confusing! The good news is that you probably won't need to use it very often. This topic is covered in detail in "Working with One-to-One Relationships" on page 84. &lt;/code&gt;&lt;code&gt;如果你想在两端配置全必须的一对一或全可选的一对一关系，Code First会需要更多的信息来获知何为主何为辅。这种Fluent API代码会让人很迷惑！好消息是你可能不需要经常这么做。这一议题将在"1-1关系"中详细讲述。 &lt;/code&gt;&lt;p&gt;&lt;strong&gt;Working with Foreign Keys&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用外键&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;So far we've just looked at relationships where there isn't a foreign key property in your class. For example, Lodging just contains a reference property that points to Destination, but there is no property to store the key value of the Destination it points to. In these cases, we have seen that Code First will introduce a foreign key in the database for you. But now let's look at what happens when we include the foreign key property in the class itself.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;到目前为止，我们只是看了在类中没有外键属性的关系。例如，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;只包含一个引用属性到&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，但没有属性来存储它指向&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;的键值。在这种情况下，我们已经看到，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;会为你的数据库引入外键。但现在让我们来看看在如果在类本身引入键属性时会发生什么。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;In the previous section you added some configuration to make the Lodging to Destination relationship required. Go ahead and remove this configuration so that we can observe the Code First conventions in action. With the configuration removed, add a DestinationId property into the Lodging class:&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;在上一节中，您添加一些配置，使&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;与&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;的关系是必须的。请删除此配置，以例&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;我们可以观察到&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;的约定行为。随着配置中删除，添加到一个&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;属性到&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;类中：&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; DestinationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Once you have added the foreign key property to the Lodging class, go ahead and run your application. The database will get recreated in response to the change you just made. If you inspect the columns of the Lodgings table, you will notice that Code First has automatically detected that DestinationId is a foreign key for the Lodging to Destination relationship and is no longer generating the Destination_DestinationId foreign key (Figure 4-3).&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;一旦你添加外键属性到&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;类，继续运行您的应用程序。该数据库将回应你刚才的改变重新创建。如果您检查&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodgings&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;表列，你会发现，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;自动检测&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;是一个外键，对应于&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;与&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;的关系，不再产生&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination_DestinationId&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;外键（图&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;4-3&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;）。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751252048.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;As you might expect by now, Code First has a set or rules it applies to try and locate a foreign key property when it discovers a relationship. The rules are based on the name of the property. The foreign key property will be discovered by convention if it is named [Target Type Key Name], [Target Type Name] + [Target Type Key Name], or [Navigation Property Name] + [Target Type Key Name]. The DestinationId property you added matched the first of these three rules. Name matching is case-insensitive, so you could have named the property DestinationID, DeStInAtIoNiD, or any other variation of casing. If no foreign key is detected, and none is configured, Code First falls back to automatically introducing one in the database.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;正如您现在可能期望的，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;有一个设置或规则得到了应用，当它发现了一个关系尝试并找到一个外键属性。规则基于的是属性的名称。外键属性，按照默认规则，应被命名为&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;[&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;目标类型的键名&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;]&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;[&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;目标类型名称&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;]+[&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;目标类型键名称&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;]&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，或&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;[&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;导航属性名称&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;]+[&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;目标类型键名称&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;]&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;。这三个规则中的第一个与您添加的属性&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;相匹配。名称匹配是区分大小写的，所以你可以有一个名为&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;DestinationID&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;DeStInAtIoNiD&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，或任何其他变化的属性，（将不会被匹配，译者注）。如果没有检测到外键，也没有配置，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;会自动在数据库中设置一个。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;code&gt;Why Foreign Key Properties? &lt;/code&gt;&lt;code&gt;为什么要使用外键属性？ &lt;/code&gt;&lt;code&gt;It's common when coding to want to identify a relationship with another class. For example, you may be creating a new Lodging and want to specify which Destination the Lodging is associated with. If the particular destination is in memory, you can set the relationship through the navigation property: &lt;/code&gt;&lt;code&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;在通常编码时，要找出一个与其他类的关系。例如，您可能会创建一个新的&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，要指定&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;与哪个&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;相关。如果特定的&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;在内存中，你就可以通过导航属性的设置关系：&lt;/span&gt;&lt;/span&gt; &lt;/code&gt;&lt;code&gt;myLodging.Destination=myDestinationInstance; &lt;/code&gt;&lt;code&gt;However, if the destination is not in memory, this would require you to first execute a query on the database to retrieve that destination so that you can set the property. There are times when you may not have the object in memory, but you do have access to that object's key value. With a foreign key property, you can simply use the key value without depending on having that instance in memory: &lt;/code&gt;&lt;code&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;但是，如果&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;不在内存中，这将要求你先执行对数据库的查询，检索&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，让你可以设置该属性。有时，你可能没有在内存中的对象，但你想访问该对象的键值。带有外键的属性，你可以简单地使用键值而不依赖于内存中的实例：&lt;/span&gt;&lt;/span&gt; &lt;/code&gt;&lt;code&gt;myLodging.DestinationId=3; &lt;/code&gt;&lt;code&gt;Additionally, in the specific case when the Lodging is new and you attach the preexisting Destination instance, there are scenarios where Entity Framework will set the Destination's state to Added even though it already exists in the database. If you are only working with the foreign key, you can avoid this problem. &lt;/code&gt;&lt;code&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;此外，在特定情况下，如果&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;是新建的，您可以附加到原有的&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;实例上，有些情况下，实体框架还要设定&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;的状态为新增，即使已经存在于数据库中。如果你只与外键进行工作，就能避免这个问题。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;p&gt;There's something else interesting that happens when you add the foreign key property.Without the DestinationId foreign key property, Code First convention allowed Lodging.Destination to be optional, meaning you could add a Lodging without a Destination. If you check back to Figure 2-1 in Chapter 2, you'll see that the Destination_DestinationId field in the Lodgings table is nullable. Now with the addition of the DestinationId property, the database field is no longer nullable and you'll find that you can no longer save a Lodging that has neither the Destination nor DestinationId property populated. This is because DestinationId is of type int, which is a value type and cannot be assigned null. If DestinationId was of type Nullable&amp;lt;int&amp;gt;, the relationship would remain optional. By convention, Code First is using the nullability of the foreign key property in your class to determine if the relationship is required or optional.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="font-family: 宋体;"&gt;还有别的有趣的现象，在添加外键属性时会发生。没有&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;&amp;nbsp;DestinationId&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;外键属性时，&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的约定规则允许&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Lodging.Destination&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;是可选的，这意味着你可以添加没有&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;。如果回到第&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;2&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;章中的图&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;2-1&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，你会看到，在&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Lodgings&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;表中&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Destination_DestinationId&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;字段可为空。现在&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;属性加入，数据库中的字段不再是可空的，你会发现，你不再可以保存没有&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;，或没有&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;属性填充的&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;数据。这是因为&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;是&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;int&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类型，这是一个值类型，不能分配&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;null&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;值。如果&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;类型是&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Nullable&amp;lt;int&amp;gt;&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;的，这种关系将保持可选的。按照规则，&lt;/span&gt;&lt;span style="font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="font-family: 宋体;"&gt;根据类中外键属性的可空性，来确定是否关系是必需的或可选的。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;code&gt;It's Just Easier with Foreign Key Properties Code First allows you define relationships without using foreign key properties in your classes. However, some of the confusing behaviors that developers encounter when working with related data in Entity Framework stems from dependent classes that do not have a foreign key property. The Entity Framework has certain rules that it follows when it checks relationship constraints, performs inserts, etc. When there's no foreign key property to keep track of a required principal (e.g., knowing what the destination is for a particular lodging), it's up to the developer to ensure that you've somehow provided the required information to EF. You can also learn more in Julie's January 2012 Data Points column, "Making Do with Absent Foreign Keys" (&lt;a href="http://msdn.com/magazine"&gt;http://msdn.com/magazine&lt;/a&gt;). &lt;/code&gt;&lt;code&gt;Code First允许你定义的类中不使用外键属性建立关系，只是使用外键属性更容易建立关系。然而，开发者在与实体框架中的相关数据工作时会遇到的一些混乱的行为源于没有外键属性可进行依赖。EF框架在检查关系约束，执行插入时会遵循一定的规则，当没有外键属性来对一个必须的主实体进行跟踪时（例如，知道一个特定的destination对应特定的lodging）时，就轮到开发者来确保你已经以某种方式提供所需信息给EF。您还可以了解更多"缺少外键下工作"（http://msdn.com/magazine），2012年1月号。&lt;/code&gt;&lt;p&gt;&lt;strong&gt;Specifying Unconventionally Named Foreign Keys&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;指定非规则命名的外键&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;What happens when you have a foreign key, but it doesn't follow Code First convention?&lt;/p&gt;&lt;p&gt;Let's introduce a new InternetSpecial class that allows us to keep track of special pricing for the various lodgings (Example 4-7). This class has both a navigation property (Accommodation) and a foreign key property (AccommodationId) for the same relationship.&lt;/p&gt;&lt;p&gt;如果有一个不遵循规则的外键会怎么样呢？&lt;/p&gt;&lt;p&gt;我们来引入一个新的InternetSpecial类，来跟踪一些各种lodging的特定价格（代码4-7）。这个类即有导航属性（Accommodation），又有外键属性（AccommodationId）,都是为同一关系设立的。&lt;/p&gt;&lt;p&gt;Example 4-7. The new InternetSpecial class&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; Model &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;InternetSpecial&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; InternetSpecialId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; Nights { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; CostUSD { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;DateTime&lt;/span&gt; FromDate { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;DateTime&lt;/span&gt; ToDate { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; AccommodationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Lodging Accommodation { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Lodging will need a new property to contain each lodging's special prices:&lt;/p&gt;&lt;p&gt;在Lodging中需要一个新的属性来包含每个logding的特定报价。&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;InternetSpecial&amp;gt; InternetSpecials { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Code First can see that Lodging has many InternetSpecials and that InternetSpecials has a Lodging (called Accommodation). Even though there's no DbSet&amp;lt;InternetSpecial&amp;gt;, InternetSpecial is reachable from Lodging and will therefore be included in the model.&lt;/p&gt;&lt;p&gt;Code First看到Lodging有很多InternetSpecials，而InternetSpecials又有一个Lodging（称之为Accommodation）.尽管没DbSet&amp;lt;InternetSpecial&amp;gt;, InternetSpecial也可以通过Lodging而包含在模型晨。&lt;/p&gt;&lt;p&gt;When you run your application again, it will create the table shown in Figure 4-4. Not only is there an AccommodationId column, which is not a foreign key, but there is also another column there which is a foreign key, Accommodation_LodgingId.&lt;/p&gt;&lt;p&gt;再次运行程序，将会创建如图4的表。不仅有不是外键的AccommodataionId列，也新增了一个外键列，Accommodation_LodgingId。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751255395.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;You've seen Code First introduce a foreign key in the database before. As early as Chapter 2, you witnessed the Destination_DestinationId field added to the Lodgings table because Code First detected a need for a foreign key. It's done the same here. Thanks to the Accommodation navigation property, Code First detected a relationship to Lodging and created the Accommodation_LodgingId field using its conventional pattern. Code First convention was not able to infer that AccommodationId is meant to be the foreign key. It simply found no properties that matched any of the three patterns that Code First convention uses to detect foreign key properties, and therefore created its own foreign key.&lt;/p&gt;&lt;p&gt;你会看到Code First引入一个外键。Code First根据Accommodation导航属性，检测到了一个对应对Lodging的关系然后使用默认规则创建了Accommodation_LodgingId字段。默认规则无法将AccommodationId推断为外键，因为Code First检查了默认规则对外键属性名称的三个要求没有在类中找到匹配项，就创建了自己的外键。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Fixing foreign key with Data Annotations&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Data Annotations修改外键&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;You can configure foreign key properties using the ForeignKey annotation to clarify your intention to Code First. Adding ForeignKey to the AccommodationId, along with information telling it which navigation property represents the relationship it is a foreign key for, will fix the problem:&lt;/p&gt;&lt;p&gt;你可以使用 Data Annotations 的配置外键特性ForeignKey来声明外键属性。在AccommodtaionId上添加ForeignKey特性告知Code First哪个导航属性是外键，来修复这个问题。&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[ForeignKey(&lt;span style="color: #a31515;"&gt;"Accommodation"&lt;/span&gt;)] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; AccommodationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Lodging Accommodation { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Alternatively, you can apply the ForeignKey annotation to the navigation property and tell it which property is the foreign key for the relationship:&lt;/p&gt;&lt;p&gt;你也可以将ForeignKey特性放在导航属性上来通知哪个属性是关系的外键。&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; AccommodationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[ForeignKey(&lt;span style="color: #a31515;"&gt;"AccommodationId"&lt;/span&gt;)] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Lodging Accommodation { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Which one you use is a matter of personal preference. Either way, you'll end up with the correct foreign key in the database: AccommodationId, as is shown in Figure 4-5.&lt;/p&gt;&lt;p&gt;两种写法都可以。与此同时，你获得的正确的的数据库外键：AccommodtationId,如图4-5所示。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751252015.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Fixing foreign key with the Fluent API&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Fluent API来修复外键&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The Fluent API doesn't provide a simple way to configure the property as a foreign key. You'll use the relationship API to configure the correct foreign key. And you can't simply configure that piece of the relationship; you'll need to first specify which relationship you want to configure (as you learned how to do earlier in this chapter) and then apply the fix.&lt;/p&gt;&lt;p&gt;To specify the relationship, begin with the InternetSpecial entity. We'll do that directly from the modelBuilder, although you can certainly create an EntityTypeConfiguration class for InternetSpecial.&lt;/p&gt;&lt;p&gt;In this case, we'll be identifying the relationship but not changing the multiplicity that Code First selected by convention. Example 4-8 specifies the existing relationship.&lt;/p&gt;&lt;p&gt;Fluent API并没有提供配置属性作为外键的简单方法。你要使用关系API来配置正确的外键。而且你不能简单地配置关系的片断，你需要首先指定你想配置的关系类型（前面已经提到）然后才应用修改。&lt;/p&gt;&lt;p&gt;为了指定关系，需要从IneternetSpecial实体开始，我们直接从modelBuilder进行配置，当然也你可以在EntityTypeConfiguration类中为InternetSpecial创建一个实例。&lt;/p&gt;&lt;p&gt;在这种情况下，我们先要设置关系而不打破Code First建立的默认关系。代码4-8指出了这种关系：&lt;/p&gt;&lt;p&gt;Example 4-8. Identifying the relationship to be configured&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;modelBuilder.Entity&amp;lt;InternetSpecial&amp;gt;() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasRequired(s =&amp;gt; s.Accommodation) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithMany(l =&amp;gt; l.InternetSpecials) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;What we want to change, however, is something about the foreign key that is also involved with this relationship. Code First expects the foreign key property to be named LodgingId or one of the other conventional names. So we need to tell it which property truly is the foreign key&amp;mdash;AccommodationId. Example 4-9 shows adding the HasForeignKey method to the relationship you specified in Example 4-8.&lt;/p&gt;&lt;p&gt;我们想要改变的，是在这种关系下的外键。Code First期待外键属性命名为LodgingId或者是其他的默认名称。因此我们需要告诉它那个属性才是真正的外键：AccommodationId.代码4-9添加了HasForeignKey方法来为关系指定外键：&lt;/p&gt;&lt;p&gt;Example 4-9. Specifying a foreign key property when it has an unconventional name&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;modelBuilder.Entity&amp;lt;InternetSpecial&amp;gt;() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasRequired(s =&amp;gt; s.Accommodation) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithMany(l =&amp;gt; l.InternetSpecials) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasForeignKey(s =&amp;gt; s.AccommodationId); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;效果与图4-5一致。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Working with Inverse Navigation Properties&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用逆导航属性&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;So far Code First has always been able to work out that the two navigation properties we have defined on each end of a relationship are in fact different ends of the same relationship. It has been able to do this because there has only ever been one possible match. For example, Lodging only contains a single property that refers to Destination (Lodging.Destination); likewise, Destination only contains a single property that references Lodging (Destination.Lodgings).&lt;/p&gt;&lt;p&gt;While it isn't terribly common, you may run into a scenario where there are multiple relationships between entities. In these cases, Code First won't be able to work out which navigation properties match up. You will need to provide some additional configuration.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;到目前为止一直能够工作，我们定义的这两个导航属性，目的不同，实际上是类似的关系。它之所以能做到这一点，因为有过一个可能的匹配。例如，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;只包含一个单一的属性，指向目的地（&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging.Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;）&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;;&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;同样地，目的地&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;只包含一个属性引用住所（&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination.Lodgings&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;）。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;虽然并不十分普遍，您可能会遇到这样一种情况：有多个实体之间的关系。在这种情况下，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;将不能够与相关导航属性相匹配。您将需要提供一些额外的配置。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;For example, what if you kept track of two contacts for each lodging? That would require a PrimaryContact and SecondaryContact property in the Lodging class. Go ahead and add these properties to the Lodging class:&lt;/p&gt;&lt;p&gt;例如，如果你想跟踪每个住所的两个联系人怎么办？这就需要在Lodging类中有一个PromaryContact和一个SecondaryContact属性。我们先将这两个属性添加到类中：&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PrimaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person SecondaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Let's also introduce the navigation properties on the other end of the relationship. This will allow you to navigate from a Person to the Lodging instances that they are primary and secondary contact for. Add the following two properties to the Person class:&lt;/p&gt;&lt;p&gt;在关系的另一端我们也需要引入导航属性。这需要让你从Person类导航到Lodging实例，知道第一联系人和第二联系人到哪里去。添加如下两个属性到Person类：&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;Lodging&amp;gt; PrimaryContactFor { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;Lodging&amp;gt; SecondaryContactFor { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Code First conventions will make the wrong assumptions about these new relationships you have just added. Because there are two sets of navigation properties, Code First is unable to work out how they match up. When Code First can't be sure which navigation properties are the inverse of each other, it will create a separate relationship for each property. Figure 4-6 shows that Code First is creating four relationships based on the four navigation properties you just added.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;将对你刚才添加的这些新的关系进行错误的假设。因为有两套导航属性，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;无法确定他们如何匹配，它会创建单独为每个属性创建关系。图&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;4-6&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;显示的&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;创建的基于您刚才添加的导航属性的四个关系。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751255362.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Code First convention can identify bidirectional relationships, but not when there are multiple bidirectional relationships between two entities. The reason that there are extra foreign keys in Figure 4-6 is that Code First was unable to determine which of the two properties in Lodging that return a Person link up to the List&amp;lt;Lodging&amp;gt; properties in the Person class.&lt;/p&gt;&lt;p&gt;You can add configuration (using Data Annotations or the Fluent API) to present this information to the model builder. With Data Annotations, you'll use an annotation called InverseProperty. With the Fluent API, you'll use a combination of the Has/With methods to specify the correct ends of these relationships.&lt;/p&gt;&lt;p&gt;You can place the annotations on either end of the relationship (or both ends if you want). We'll stick them on the navigation properties in the Lodging class (Example 4-10). The InverseProperty Data Annotation needs the name of the corresponding navigation property in the related class as its parameter.&lt;/p&gt;&lt;p&gt;Code First默认规则可以识别双向关系，但不能识别在两个实体中多个双向关系。原因是会多如图4-6所示的多个外键，使得！CF无法确定哪个在Lodging的属性连接到Person类的哪个List&amp;lt;Lodging&amp;gt;属性。&lt;/p&gt;&lt;p&gt;你可以添加配置（使用Data Annotations或Fluent API）来明示这些信息给modelBuilder。使用Data Annotations，你需要使用一个特性标记叫做InverseProperty。使用Fluent API，需要合并使用Has/With方法指定这些关系正确的端点。&lt;/p&gt;&lt;p&gt;你可将特性标记放在关系的任何一端（或两端都放）。我们将其放在Lodging类中（代码4-10）。InverseProperty特性标记需要相关类中相应导航属性作为参数。&lt;/p&gt;&lt;p&gt;Example 4-10. Configuring multiple bidirectional relationships from Lodging to Person&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[InverseProperty(&lt;span style="color: #a31515;"&gt;"PrimaryContactFor"&lt;/span&gt;)] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PrimaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[InverseProperty(&lt;span style="color: #a31515;"&gt;"SecondaryContactFor"&lt;/span&gt;)] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person SecondaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;With the Fluent API, you need to use the Has/With pattern that you learned about earlier to identify the ends of each relationship. The first configuration in Example 4-11 describes the relationship with Lodging.PrimaryContact on one end and Person.Primary ContactFor on the other. The second configuration is for the relationship between SecondaryContact and SecondaryContactFor.&lt;/p&gt;&lt;p&gt;使用Fluent API，你需要使用Has/With语句来指定关系的两端。第一个配置见代码4-11来描述关系 ，一端为Lodging.PrimaryContact，另一端为Person.Primary ContactFor。第二个配置是针对SecondaryContact和SecondaryContactFor两者关系建立的。&lt;/p&gt;&lt;p&gt;Example 4-11. Configuring multiple relationships fluently&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;modelBuilder.Entity&amp;lt;Lodging&amp;gt;() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasOptional(l =&amp;gt; l.PrimaryContact) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithMany(p =&amp;gt; p.PrimaryContactFor); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;modelBuilder.Entity&amp;lt; Lodging &amp;gt;() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasOptional(l =&amp;gt; l.SecondaryContact) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithMany(p =&amp;gt; p.SecondaryContactFor); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Working with Cascade Delete&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用级连删除&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Cascade delete allows dependent data to be automatically deleted when the principal record is deleted. If you delete a Destination, for example, the related Lodgings will also be deleted automatically. Entity Framework supports cascade delete behavior for in memory data as well as in the database. As discussed in Chapter 19 of the second edition of Programming Entity Framework, it is recommended that you implement cascade delete on entities in the model if their mapped database objects also have cascade delete defined.&lt;/p&gt;&lt;p&gt;级联删除允许主记录被删除时相关联的依赖性数据也被删除。例如，如果你删除Destinantion，相关的Lodgings会被自动删除。EF框架支持对内存中和数据库中的数据进行级联删除。在"用EF框架编程"第二版第19章，推荐你为模型实体配置级联删除，所映射的数据库对象也会具有级联删除的定义。&lt;/p&gt;&lt;p&gt;By convention, Code First switches on cascade delete for required relationships. When a cascade delete is defined, Code First will also configure a cascade delete in the database that it creates. Earlier in this chapter we looked at making the Lodging to Destination relationship required. In other words, a Lodging cannot exist without a Destination. Therefore, if a Destination is deleted, any related Lodgings (that are in memory and being change-tracked by the context) will also be deleted. When SaveChanges is called, the database will delete any related rows that remain in the Lodgings table, using its cascade delete behavior.&lt;/p&gt;&lt;p&gt;默认规则约定，Code First会对必须的关系设置级联删除。当一个级联删除定义后，Code First会在数据库中为其创建级联删除。在本章前面我们已经将Lodging和Destination的关系设定为必须。换句话说，没有Destination，Lodging也不存在。因此，如果删除一个Destination，任何相关联的Lodging（在内存中且被上下文所跟踪）也会被删除。当提交SaveChanges，数据库会删除任何保存在Lodgings表中的相关行，使用的就是级联删除行为。&lt;/p&gt;&lt;p&gt;Looking at the database, you can see that Code First carried through the cascade delete and set up a constraint on the relationship in the database. Notice the Delete Rule in Figure 4-7 is set to Cascade.&lt;/p&gt;&lt;p&gt;再看数据库，你会看到Code First实施了级联删除并且在数据库之间的关系上添加了约束。请注意图4-7的删除规则设定了级联。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751251425.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Example 4-12 shows a new method called DeleteDestinationInMemoryAndDbCascade, which we'll use to demonstrate the in-memory and database cascade delete.&lt;/p&gt;&lt;p&gt;代码4-12是一个新方法叫做DeleteDestinationInMemoryAndDbCascade，用于展示内存中和数据库中的级联删除。&lt;/p&gt;&lt;p&gt;Example 4-12. A method to explore cascade deletes&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; DeleteDestinationInMemoryAndDbCascade() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;int&lt;/span&gt; destinationId; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (var context = &lt;span style="color: blue;"&gt;new&lt;/span&gt; BreakAwayContext()) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var destination = &lt;span style="color: blue;"&gt;new&lt;/span&gt; Destination &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Name = &lt;span style="color: #a31515;"&gt;"Sample Destination"&lt;/span&gt;, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Lodgings = &lt;span style="color: blue;"&gt;new&lt;/span&gt; List&amp;lt;Lodging&amp;gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;new&lt;/span&gt; Lodging { Name = &lt;span style="color: #a31515;"&gt;"Lodging One"&lt;/span&gt; }, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;new&lt;/span&gt; Lodging { Name = &lt;span style="color: #a31515;"&gt;"Lodging Two"&lt;/span&gt; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;}; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.Destinations.Add(destination); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.SaveChanges(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;destinationId = destination.DestinationId; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (var context = &lt;span style="color: blue;"&gt;new&lt;/span&gt; BreakAwayContext()) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var destination = context.Destinations &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.Include(&lt;span style="color: #a31515;"&gt;"Lodgings"&lt;/span&gt;) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.Single(d =&amp;gt; d.DestinationId == destinationId); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var aLodging = destination.Lodgings.FirstOrDefault(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.Destinations.Remove(destination); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Console.WriteLine(&lt;span style="color: #a31515;"&gt;"State of one Lodging: {0}"&lt;/span&gt;, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.Entry(aLodging).State.ToString()); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.SaveChanges(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;The code uses a context to insert a new Destination with a couple of Lodgings. It then saves these Lodgings to the database and records the primary of the new Destination. In a separate context, the code then retrieves the Destination and its related Lodgings, and then uses the Remove method to mark the Destination instance as Deleted. We use Console.WriteLine to inspect the state of one of the related Lodging instances that are in memory. We'll do this using the Entry method of DbContext. The Entry method gives us access to the information that EF has about the state of a given object. Next, the call to SaveChanges persists the deletions to the database.&lt;/p&gt;&lt;p&gt;代码使用context插入了一个新Destination，有两个Lodging.然后将这些Lodging储存进数据库然后记录了新添加的Destination。在一个单独的context里，代码取出Destination和其相关的Lodging，然后使用Remove方法标记Destination实例为删除，我们使用Console.WriteLine来检测相关Lodging实例在内存中状态，这使用了一个DbContext的Entry方法。Entry方法能够让我们访问EF施加给给定对象的状态信息。最后，调用SaveChanges方法持久化删除信息到数据库。&lt;/p&gt;&lt;p&gt;After calling Remove on the Destination, the state of a Lodging is displayed in the console window. It is Deleted also even though we did not explicitly remove any of the Lodgings. That's because Entity Framework used client-side cascade deleting to delete the dependent Lodgings when the code explicitly deleted (Removed) the destination.&lt;/p&gt;&lt;p&gt;Next, when SaveChanges is called, Entity Framework sent three DELETE commands to the database, as shown in Figure 4-8. The first two are to delete the related Lodging instances that were in memory and the third to delete the Destination.&lt;/p&gt;&lt;p&gt;调用Destination的Remove方法，Lodging的状态显示在控制台窗口。尽管我们并没有显示地要求删除任何Lodging，但仍显示出了删除命令。这是因为当我们显示地删除Destination时，EF框架使用客户端的级联删除功能删除了依赖的Lodging。&lt;/p&gt;&lt;p&gt;下一步，当SaveChanges方法调用时，EF框架发送三个DELERE命令到数据库。如图4-8所示，前两删除命令是对相关Lodging实例进行删除，第三个才是删除Destination,&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751262821.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Now let's change the method. We'll remove the eager loading (Include) that pulled the Lodging data into memory along with Destination. We'll also remove all of the related code that mentions the Lodgings. Since there are no Lodgings in memory, there will be no client-side cascade delete, but the database should clean up any orphaned Lodgings because of the cascade delete defined in the database (Figure 4-7). The revised method is listed in Example 4-13.&lt;/p&gt;&lt;p&gt;现在我们来改变一下方法。我们将要要随同Destination一起删除以前存入的Loading数据。我们删除与Lodging提到的所有相关代码。由于内存中无Lodging，就不会有客户端的级联删除，而数据库却清除了任何孤立的Lodgings数据，这是因为在数据库中定义了级联删除。（见图4-7）修改的方法见代码4-13.&lt;/p&gt;&lt;p&gt;Example 4-13. Modified DeleteDestinationInMemoryAndDbCascade code&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; DeleteDestinationInMemoryAndDbCascade() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;int&lt;/span&gt; destinationId; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (var context = &lt;span style="color: blue;"&gt;new&lt;/span&gt; BreakAwayContext()) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var destination = &lt;span style="color: blue;"&gt;new&lt;/span&gt; Destination &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Name = &lt;span style="color: #a31515;"&gt;"Sample Destination"&lt;/span&gt;, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Lodgings = &lt;span style="color: blue;"&gt;new&lt;/span&gt; List&amp;lt;Lodging&amp;gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;new&lt;/span&gt; Lodging { Name = &lt;span style="color: #a31515;"&gt;"Lodging One"&lt;/span&gt; }, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;new&lt;/span&gt; Lodging { Name = &lt;span style="color: #a31515;"&gt;"Lodging Two"&lt;/span&gt; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;}; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.Destinations.Add(destination); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.SaveChanges(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;destinationId = destination.DestinationId; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (var context = &lt;span style="color: blue;"&gt;new&lt;/span&gt; BreakAwayContext()) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var destination = context.Destinations &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.Single(d =&amp;gt; d.DestinationId == destinationId); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.Destinations.Remove(destination); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.SaveChanges(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (var context = &lt;span style="color: blue;"&gt;new&lt;/span&gt; BreakAwayContext()) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var lodgings = context.Lodgings &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.Where(l =&amp;gt; l.DestinationId == destinationId).ToList(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Console.WriteLine(&lt;span style="color: #a31515;"&gt;"Lodgings: {0}"&lt;/span&gt;, lodgings.Count); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;When run, the only command sent to the database is one to delete the destination. The database cascade delete will delete the related lodgings in response. When querying for the Lodgings at the end, since the database deleted the lodgings, the query will return no results and the lodgings variable will be an empty list.&lt;/p&gt;&lt;p&gt;运行后，发送到数据库的唯一命令是删除destination。数据库级联删除响应的相关Lodging。当在Lodgings端查询时，由于数据库删除了lodgings,查询不会返回结果，lodgings变量成为一空的列表。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Turning On or Off Client-Side Cascade Delete with Fluent Configurations&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Fluent API配置打开或关闭客户端级联删除功能&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;You might be working with an existing database that does not use cascade delete or you may have a policy of being explicit about data removal and not letting it happen automatically in the database. If the relationship from Lodging to Destination is optional, this is not a problem, since by convention, Code First won't use cascade delete with an optional relationship. But you may want a required relationship in your classes without leveraging cascade delete.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;你可能会在现有的数据库上工作，不使用级联删除或者你可能有一个规则必须显示删除数据，不允许在数据库中自动删除。如果从&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;到&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;之间的关系是可选的，这不是一个问题，因为按照默认规则，&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Code First&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;不能在可选的关系上使用级联删除。但你可能需要即有必须的关系，又不想使用级联删除功能。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;You may want to get an error if the user of your application tries to delete a Destination and hasn't explicitly deleted or reassigned the Lodging instances assigned to it. For the scenarios where you want a required relationship but no cascade delete, you can explicitly override the convention and configure cascade delete behavior with the Fluent API. This is not supported with Data Annotations.&lt;/p&gt;&lt;p&gt;你可能想在你的应用程序试图删除一个Destination时向用户返回一个错误，这是在没有显示地删除或重新给这个Destination分配Lodging实例时出现的。在这种情况下，你就需要一个必须的关系而不需要级联删除，你可以显示地覆写默认规则而使用Fluent API来对级联删除进行配置。这个功能Data Annotations不支持。&lt;/p&gt;&lt;p&gt;Keep in mind that if you set the model up this way, your application code will be responsible for deleting or reassigning dependent data when necessary.&lt;/p&gt;&lt;p&gt;The Fluent API method to use is called WillCascadeOnDelete and takes a Boolean as a parameter. This configuration is applied to a relationship, which means that you first need to specify the relationship using a Has/With pairing and then call WillCascadeOnDelete.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;请记住，如果你成立这样的模型，应用程序代码将会实现负责任地删除或在必要时重新分配相关的数据。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Fluent API&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;使用的方法是&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;WillCascadeOnDelete&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，以一个布尔值作为参数。此配置适用于有关系，这意味着你首先需要使用指定的一个配对的关系，然后调用&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;WillCascadeOnDelete&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;方法。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Working within the LodgingConfiguration class, the relationship is defined as:&lt;/p&gt;&lt;p&gt;在LodgingConfiguration类中，关系定义为：&lt;/p&gt;&lt;p&gt;HasRequired(l=&amp;gt;l.Destination)&lt;/p&gt;&lt;p&gt;.WithMany(d=&amp;gt;d.Lodgings)&lt;/p&gt;&lt;p&gt;From there, you'll find three possible configurations to add. WillCascadeOnDelete is&lt;/p&gt;&lt;p&gt;one of them, as you can see in Figure 4-9.&lt;/p&gt;&lt;p&gt;在这里，有三个可能的配置可供添加。WillCascadeOnDelete是其中之一，如图4-9所示。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751265852.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Now you can set WillCascadeOnDelete to false for this relationship:&lt;/p&gt;&lt;p&gt;现在你可以设置此关系的WillCascadeOnDelete为false：&lt;/p&gt;&lt;p&gt;HasRequired(l=&amp;gt;l.Destination)&lt;/p&gt;&lt;p&gt;.WithMany(d=&amp;gt;d.Lodgings)&lt;/p&gt;&lt;p&gt;.WillCascadeOnDelete(false)&lt;/p&gt;&lt;p&gt;This will also mean that the database schema that Code First generates will not include the cascade delete. The Delete Rule that was Cascade in Figure 4-7 would become No Action.&lt;/p&gt;&lt;p&gt;这也意味着Code First生成的数据库架构将不会包含级联删除。如图4-7所示的级联删除规则将不会出现。&lt;/p&gt;&lt;p&gt;In the scenario where the relationship is required, you'll need to be aware of logic that will create a conflict, for example, the current required relationship between Lodging and Destination that requires that a Lodging instance have a Destination or a DestinationId. If you have a Lodging that is being change-tracked and you delete its related Destination, this will cause Lodging.Destination to become null. When SaveChanges is called, Entity Framework will attempt to synchronize Lodging.DestinationId, setting it to null. But that's not possible and an exception will be thrown with the following detailed message:&lt;/p&gt;&lt;p&gt;在关系为必须的场景下，你应该意识到这种逻辑会创建一个冲突，例如，&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;目前在&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;和&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;的必须关系中，需要一个&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;实例有一个&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;estination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;或一个&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;DestinationId&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;。如果你有一个正在变化的跟踪，并删除了相关的&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，这将导致&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging.Destination&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;为空。调用&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;SaveChanges&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;时，实体框架将尝试同步&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;Lodging.DestinationId&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;，设置为&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: Arial;"&gt;NULL&lt;/span&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;。但是，这是不行的，异常将抛出下面的详细信息：&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.&lt;/p&gt;&lt;p&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体; color: #333333;"&gt;系不能改变，因为一个或多个外键的属性非空。当一个变化是一个关系，相关的外键的属性设置为空值。如果外键不支持空值，必须定义一个新的关系，外键的属性必须指派另一个非空值，必须删除无关的对象。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The overall message here is that you have control over the cascade delete setting, but you will be responsible for avoiding or resolving possible validation conflicts caused by not having a cascade delete present.&lt;/p&gt;&lt;p&gt;&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;这里的整体信息是，你必须控制级联删除设置，并且为避免或解决验证没有级联删除可能引起的冲突负责。&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Setting Cascade Delete Off in Scenarios That Are Not Supported by the Database&lt;/p&gt;&lt;p&gt;对不被数据库所支持的场合关闭级联删除&lt;/p&gt;&lt;p&gt;Some databases (including SQL Server) don't support multiple relationships that specify cascade delete pointing to the same table. Because Code First configures required relationships to have cascade delete, this results in an error if you have two required relationships to the same entity. You can use WillCascadeOnDelete(false) to turn off the cascade delete setting on one or more of the relationships. Example 4-14 shows an example of the exception message from SQL Server if you don't configure this correctly.&lt;/p&gt;&lt;p&gt;许可数据库（包括SQL Server）不支持指定级联删除指向到同一个表的多重关系。由于Code First配置的必须关系包括级联删除，如果有两个必须关系指向同一个实体就会出现错误。你可以使用WillCascadeOnDelete(false)来关闭级一个或多个联删除设置。代码4-14显示了如果不进行正确配置来自于SQL Server的异常信息。&lt;/p&gt;&lt;p&gt;Example 4-14. Exception message when Code First attempts to create cascade delete where multiple relationships exist&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; color: blue; font-size: 9pt;"&gt;System&lt;span style="color: gray;"&gt;.&lt;span style="color: teal;"&gt;InvalidOperationException&lt;/span&gt; &lt;span style="color: teal;"&gt;was&lt;/span&gt; &lt;span style="color: teal;"&gt;unhandled&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;Message&lt;span style="color: gray;"&gt;=&lt;span style="color: teal;"&gt;The&lt;/span&gt; &lt;span style="color: blue;"&gt;database&lt;/span&gt; &lt;span style="color: teal;"&gt;creation&lt;/span&gt; &lt;span style="color: teal;"&gt;succeeded&lt;span style="color: gray;"&gt;,&lt;/span&gt; but&lt;/span&gt; &lt;span style="color: teal;"&gt;the&lt;/span&gt; &lt;span style="color: teal;"&gt;creation&lt;/span&gt; &lt;span style="color: blue;"&gt;of&lt;/span&gt; &lt;span style="color: teal;"&gt;the&lt;/span&gt; &lt;span style="color: blue;"&gt;database&lt;/span&gt; &lt;span style="color: lime;"&gt;objects&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: teal;"&gt;did&lt;/span&gt; &lt;span style="color: gray;"&gt;not.&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: teal;"&gt;See&lt;/span&gt; &lt;span style="color: teal;"&gt;InnerException&lt;/span&gt; &lt;span style="color: blue;"&gt;for&lt;/span&gt; &lt;span style="color: teal;"&gt;details&lt;span style="color: gray;"&gt;.&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;InnerException:&lt;/span&gt; &lt;span style="color: blue;"&gt;System&lt;span style="color: gray;"&gt;.&lt;span style="color: teal;"&gt;Data&lt;span style="color: gray;"&gt;.&lt;span style="color: teal;"&gt;SqlClient&lt;span style="color: gray;"&gt;.&lt;span style="color: teal;"&gt;SqlException&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;Message&lt;span style="color: gray;"&gt;=&lt;span style="color: teal;"&gt;Introducing&lt;/span&gt; &lt;span style="color: blue;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color: blue;"&gt;KEY&lt;/span&gt; &lt;span style="color: blue;"&gt;constraint&lt;/span&gt; &lt;span style="color: red;"&gt;'Lodging_SecondaryContact'&lt;/span&gt; &lt;span style="color: blue;"&gt;on&lt;/span&gt; &lt;span style="color: blue;"&gt;table&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: red;"&gt;'Lodgings'&lt;/span&gt; &lt;span style="color: teal;"&gt;may&lt;/span&gt; &lt;span style="color: teal;"&gt;cause&lt;/span&gt; &lt;span style="color: teal;"&gt;cycles&lt;/span&gt; &lt;span style="color: gray;"&gt;or&lt;/span&gt; &lt;span style="color: teal;"&gt;multiple&lt;/span&gt; &lt;span style="color: blue;"&gt;cascade&lt;/span&gt; &lt;span style="color: teal;"&gt;paths&lt;span style="color: gray;"&gt;.&lt;/span&gt; Specify&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;/span&gt; &lt;span style="color: blue;"&gt;DELETE&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;NO&lt;/span&gt; &lt;span style="color: blue;"&gt;ACTION&lt;/span&gt; &lt;span style="color: gray;"&gt;or&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;/span&gt; &lt;span style="color: blue;"&gt;UPDATE&lt;/span&gt; &lt;span style="color: blue;"&gt;NO&lt;/span&gt; &lt;span style="color: blue;"&gt;ACTION&lt;span style="color: gray;"&gt;,&lt;/span&gt; &lt;span style="color: gray;"&gt;or&lt;/span&gt; modify&lt;/span&gt; &lt;span style="color: teal;"&gt;other&lt;/span&gt; &lt;span style="color: blue;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color: blue;"&gt;KEY&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: teal;"&gt;constraints&lt;span style="color: gray;"&gt;.&lt;/span&gt; Could&lt;/span&gt; &lt;span style="color: gray;"&gt;not&lt;/span&gt; &lt;span style="color: blue;"&gt;create&lt;/span&gt; &lt;span style="color: blue;"&gt;constraint&lt;span style="color: gray;"&gt;.&lt;/span&gt; &lt;span style="color: teal;"&gt;See&lt;/span&gt; &lt;span style="color: teal;"&gt;previous&lt;/span&gt; &lt;span style="color: teal;"&gt;errors&lt;span style="color: gray;"&gt;. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;code&gt;Consider Performance Implications of Client-Side Cascade Delete &lt;/code&gt;&lt;code&gt;考虑客户端级联删除对性能的影响 &lt;/code&gt;&lt;code&gt;Whether you are using Code First, Database First, or Model First, you should keep in mind the performance implications of cascade delete. If you delete a principal, or "parent," without having the related object(s) in memory, the database will take care of the cascade delete. If you pull all of the related objects into memory and let the client-side cascade delete affect those related objects, then call SaveChanges, SaveChanges will send DELETE commands to the database for each of those related objects. There may be cases where those related objects are in memory and you do indeed want them to be deleted. But if you don't need them in memory and can rely on the database to do the cascade delete, you should consider avoiding pulling them into memory. &lt;/code&gt;&lt;code&gt;不管你是使用Code First，还是用Database First, Model First，你都要记住级联删除的性能影响。如果你删除了一个上级主题，或者"父"主题，如果内存中没有相关对象，数据库本身就会实施级联删除。如果你将所有相关对象调入内存，让客户端级联删除影响这些对象，在调用SaveChanges方法时，saveChange将会发送针对这些相关对象的Delete命令到数据库。&lt;span style="color: #333333;"&gt;&lt;span style="background-color: whitesmoke; font-family: 宋体;"&gt;可能有情况下，这些相关对象在内存中，你真的希望他们能够被删除。但是，如果你不需要在内存中，并可以依靠的数据库做级联删除，你应该考虑避免他们放入内存。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;p&gt;&lt;strong&gt;Exploring Many-to-Many Relationships&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;探索多对多关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Entity Framework supports many-to-many relationships. Let's see how Code First responds to a many-to-many relationship between two classes when generating a database.&lt;/p&gt;&lt;p&gt;EF框架支持多对多关系。让我们来看看Code First是如何在生成数据库时响应类间的多对多关系。&lt;/p&gt;&lt;p&gt;If you've had many-to-many relationships when using the database-first strategy, you may be familiar with the fact that Entity Framework can create many-to-many mappings when the database join table contains only the primary keys of the related entities. This mapping rule is the same for Code First.&lt;/p&gt;&lt;p&gt;在使用database first策略时如果有多对多关系，你可能熟悉EF框架可以创建多对多映射，条件是数据库内联表只包含相关实体的主键。这种映射规则也适用于Code First。&lt;/p&gt;&lt;p&gt;Let's add a new Activity class to the model. Activity, shown in Example 4-15, will be related to the Trip class. A Trip can have a number of Activities scheduled and an Activity can be scheduled for a variety of trips. Therefore Trip and Activity will have a many-to-many relationship.&lt;/p&gt;&lt;p&gt;我们添加一个新的类：Acitivity到模型中，如代码4-15，将于Trip类相关联。一个Trip类可以有一些Activites日程，而一个Activity日程又可以计划好几个trips(行程)。因此Trip和Activity就会有多对多关系。&lt;/p&gt;&lt;p&gt;Example 4-15. A new class, Activity&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.ComponentModel.DataAnnotations; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Collections.Generic; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; Model &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Activity&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; ActivityId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[Required, MaxLength(50)] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;Trip&amp;gt; Trips { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;There's a List&amp;lt;Trip&amp;gt; in the Activity class. Let's also add a List&amp;lt;Activity&amp;gt; to the Trip class for the other end of the many-to-many relationship:&lt;/p&gt;&lt;p&gt;在Activity类中有一个List&amp;lt;Trip&amp;gt;，我们也添加了一个List&amp;lt;Activity&amp;gt;到Trip类到另一端形成多对多关系。&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;Activity&amp;gt; Activities { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;When you run the application again, Code First will recreate the database because of the model changes. Code First convention will recognize the many-to-many relationship and build a join table in the database with the appropriate keys of the tables it's joining. The keys are both primary keys of the join table and foreign keys pointing to the joined tables, as shown in Figure 4-10.&lt;/p&gt;&lt;p&gt;再次运行程序，因为模型变化Code First将重新创建数据库。Code First根据默认规则识别出了多对多关系，建立了内联表，并配置了合适的键。两个内联表的主键都作为外键指向了内联表，如图4-10所示。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751265819.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Notice that Code First convention created the table name by combining the names of the classes it's joining and then pluralizing the result. It also used the same pattern we've seen earlier for creating the foreign key names. In Chapter 5, which focuses on table and column mappings, you'll learn how to specify the table name and column names of the join table with configurations.&lt;/p&gt;&lt;p&gt;注意到Code First的默认规则创建的表名合并使用了两个类的类名。它也使用了我们在前面创建外键使用的模式来创建外键。在第5章，我们将关注于表和列的映射，到时你会学习到如何使用配置为内联表指定表名和列名。&lt;/p&gt;&lt;p&gt;Once the many-to-many relationship exists, it behaves in just the same way that many-to-many relationships have worked in Entity Framework since the first version. You can query, add, and remove related objects by using the class properties. In the background, Entity Framework will use its knowledge of how your classes map to the database to create select, insert, update, and delete commands that incorporate the join table.&lt;/p&gt;&lt;p&gt;一旦多对对关系建立，其行为就与EF早期版本中多对多关系所表现出来的是一样的。你可以通过类属性查询，添加和删除相关对象。在后台，EF框架将使用它的内置特性来协助数据库创建集成的内联表的select,insert,update和delete命令。&lt;/p&gt;&lt;p&gt;For example, the following query looks for a single trip and eager loads the related Activities:&lt;/p&gt;&lt;p&gt;例如，如下的查询寻找一次单独的trip和计划实施的相关Activities.&lt;/p&gt;&lt;p&gt;var tripWithActivities = context.Trips&lt;/p&gt;&lt;p&gt;.Include("Activities").FirstOrDefault();&lt;/p&gt;&lt;p&gt;The query is written against the classes with no need to be concerned about how the trip and its activities are joined in the database. Entity Framework uses its knowledge of the mappings to work out the SQL that performs the join and returns a graph that includes all of the activities that are bound to the first trip. This may not be exactly how you would construct the SQL, but remember that Entity Framework constructs the store SQL based on a pattern that can be used generically regardless of the structure of your classes or the schema of the database.&lt;/p&gt;&lt;p&gt;查询是对类进行的，没有必要关心trip和activities是怎样在数据库连接的。EF框架会自行配置SQL语句执行内联，并返所有适合于第一条trip的所有activities记录。这确实不需要自行构建SQL语句，但一定要记住不管你的类的结构或数据库构架如何，EF框架构建的SQL都是可以通用的。&lt;/p&gt;&lt;p&gt;The result is a graph of the trip and its activities. Figure 4-11 shows the Trip in a debug window. You can see it has two Activities that were pulled back from the database along with the Trip.&lt;/p&gt;&lt;p&gt;输出的结果是trip和其activities的图。图4-11显示了Trip类在一个调试窗口的信息。你可以看到其包含两个activites，都最从数据库中提取出来匹配这次Trip的。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751266343.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751266866.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Entity Framework took care of the joins to get across the join table without you having to be aware of its presence. In the same way, any time you do inserts, updates, or deletes within this many-to-many relationship, Entity Framework will work out the proper SQL for the join without you having to worry about it in your code.&lt;/p&gt;&lt;p&gt;不必知道它的存在，EF框架会维护内联表并跨越内联表。同样地，任何时候你进行插入，更新或删除操作，EF框架将制定出正确的内联SQL语句，不用在你的代码中作任何关注。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Working with Relationships that Have Unidirectional Navigation&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用单边导航的关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;So far we have looked at relationships where a navigation property is defined in both classes that are involved in the relationship. However, this isn't a requirement when working with the Entity Framework.&lt;/p&gt;&lt;p&gt;In your domain, it may be common place to navigate from a Destination to its associated Lodging options, but a rarity to navigate from a Lodging to its Destination. Let's go ahead and remove the Destination property from the Lodging class (Example 4-16).&lt;/p&gt;&lt;p&gt;到目前为止我们已经观察了导航属性已经定义在两个类中的关系。但是，EF框架工作这并不是必须的。&lt;/p&gt;&lt;p&gt;在你的域中，从Destination导航到其相关的Lodging选项是一种通常的情况，但是可能很少需要从Lodging导航回Destination.让我们将Destination从Lodging类中移走（代码4-16）。&lt;/p&gt;&lt;p&gt;Example 4-16. Navigation property removed from Lodging class&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Lodging&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LodgingId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Owner { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsResort { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; MilesFromNearestAirport { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; DestinationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: green;"&gt;//public Destination Destination { get; set; }&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;InternetSpecial&amp;gt; InternetSpecials { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PrimaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person SecondaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Entity Framework is perfectly happy with this; it has a very clear relationship defined from Lodging to Destination with the Lodgings property in the Destination class. This still causes the model builder to look for a foreign key in the Lodging class and Lodging.DestinationId satisfies the convention.&lt;/p&gt;&lt;p&gt;Now let's go one step further and remove the foreign key property from the Lodging class, as shown in Example 4-17.&lt;/p&gt;&lt;p&gt;EF框架很高兴看到这种情况。这里清晰地定义了从Lodging到Destination之间的关系，依据的是Destination类中的Lodgings属性。这仍然会使用模型构建器到Lodging类和中去寻找外键Lodging.DestinationId满足默认规则。&lt;/p&gt;&lt;p&gt;现在我们前进一步，将Lodging类中的外键属性删除，如代码4-17.&lt;/p&gt;&lt;p&gt;Example 4-17. Foreign key commented out&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Lodging&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LodgingId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Owner { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsResort { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; MilesFromNearestAirport { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: green;"&gt;//public int DestinationId { get; set; }&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: green;"&gt;//public Destination Destination { get; set; }&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Remember the Code First convention that will introduce a foreign key if you don't define one in your class? That same convention still works when only one navigation property is defined in the relationship. Destination still has a property that defines its relationship to Lodging. In Figure 4-13 you can see that a Destination_DestinationId column is added into the Lodgings table. You might recall that the convention for naming the foreign key column was [Navigation Property Name] + [Primary Key Name]. But we no longer have a navigation property on Lodging. If no navigation property is defined on the dependent entity, Code First will use [Principal Type Name] + [Primary KeyName]. In this case, that happens to equate to the same name.&lt;/p&gt;&lt;p&gt;是否还记得如果不不定义一个外键在你的类中Code First默认规则会自动引入一个？同样的规则适用于在单边定义的导航属性。Destination仍然有一个属性定义 了到Lodging的关系。图4-13显示了有一个Destination_DestinationId列加入到的Lodgings表中。这可能会使你回想起有关外键列的命名规则：[Navigation Property Name] + [Primary Key Name]。但是我们在Lodgin类里不再有一个导航属性。如果在依赖实体中没有导航属性加以定义，Code First将会使用[Principal Type Name] + [Primary KeyName].在这种情况下，等于于同一个名字。&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751271849.png" alt="" /&gt;&lt;/p&gt;&lt;code&gt;What if we tried to just define a foreign key and no navigation properties in either class? Entity Framework itself supports this scenario, but Code First does not. Code First requires at least one navigation property to create a relationship. If you remove both navigation properties, Code First will just treat the foreign key property as any other property in the class and will not create a foreign key constraint in the database. &lt;/code&gt;&lt;code&gt;那么如果我们试图在另一个类中只定义外键而没有导航属性呢，EF框架本身支持这种情况，但Code First不支持。Code First需要至少一个导航属性来创建关系。如果你移除了两边的导航属性，Code First将只将外键属性作为任何类中的其他属性而不会在数据库中创建约束。 &lt;/code&gt;&lt;p&gt;Now let's change the foreign key property to something that won't get detected by convention. Let's use LocationId instead of DestinationId, as shown in Example 4-18. Remember that we have no navigation property; it's still commented out.&lt;/p&gt;&lt;p&gt;现在我将外键属性调整为默认规则无法检测到的情况。我们用LocationId替代DestinationId,如代码4-16.记住我们没有导航属性，仍然被注释着。&lt;/p&gt;&lt;p&gt;Example 4-18. Foreign key with unconventional name&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Lodging&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LodgingId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Owner { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsResort { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; MilesFromNearestAirport { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LocationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: green;"&gt;//public Destination Destination { get; set; }&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;InternetSpecial&amp;gt; InternetSpecials { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PrimaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person SecondaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Thanks to Destination.Lodgings, Code First knows about the relationship between the two classes. But it cannot find a conventional foreign key. We've been down this road before. All we had to do was add some configuration to identify the foreign key.&lt;/p&gt;&lt;p&gt;感谢Destination.Lodgings，Code First知道两个类中存在关系。但它无法找到一个符合约定的外键。我们之前已经铺了路，现在还需要一些配置来帮助Code First识别外键。&lt;/p&gt;&lt;p&gt;In previous examples, we placed the ForeignKey annotation on the navigation property in the dependent class or we placed it on the foreign key property and told it which navigation property it belonged to. But we no longer have a navigation property in the dependent class. Fortunately, we can just place the data annotation on the navigation property we do have (Destination.Lodgings). Code First knows that Lodging is the dependent in the relationship, so it will search in that class for the foreign key:&lt;/p&gt;&lt;p&gt;在前面的例子里，我们将ForeignKey特性标记放在依赖类的导航属性或者将其放在外键属性上，告知哪个导航属性属于它。但我们在依赖类中不再有一个导航属性。幸运的是，我们可以将Data Annotations的标记放在导航属性上（Destination.Lodgings）。Code First知道Lodging是关系中的依赖类，因此它会为外键在此类中寻找有关字段：&lt;/p&gt;&lt;p&gt;[ForeignKey("LocationId")]&lt;/p&gt;&lt;p&gt;public List&amp;lt;Lodging&amp;gt; Lodgings { get; set; }&lt;/p&gt;&lt;p&gt;The Fluent API also caters to relationships that only have one navigation property. The Has part of the configuration must specify a navigation property, but the With part can be left empty if there is no inverse navigation property. Once you have specified the Has and With sections, you can call the HasForeignKey method you used earlier:&lt;/p&gt;&lt;p&gt;Fluent API也能为这种单侧导航属性创建关系。配置的Has部分必须指定一个导航属性，而With部分如果没有反向导航属性就留空。一旦指定了Has和With语句，就可以调用HasForeignKey方法：&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;modelBuilder.Entity&amp;lt;Destination&amp;gt;() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasMany(d =&amp;gt; d.Lodgings) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.WithRequired() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;.HasForeignKey(l =&amp;gt; l.LocationId); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;While a unidirectional relationship may make sense in some scenarios, we want to be able to navigate from a Lodging to its Destination. Go ahead and revert the changes to the Lodging class. Uncomment the Destination property and rename the foreign key property back to DestinationId, as shown in Example 4-19. You'll also need to remove the ForeignKey annotation from Destination.Lodging and remove the above Fluent API configuration if you added it.&lt;/p&gt;&lt;p&gt;在我们需要创建单边关系时，很多情况下我们想要从Lodgin导航回相应的Destination。我们恢复对Lodging类的调整。取消对Destination属性的注释并将外键属性恢复为，如代码4-19.你也需要将ForegnKey标记从Destination.Lodging上移除，并移动上述刚刚添加的Fluent API配置。&lt;/p&gt;&lt;p&gt;Example 4-19. Lodging class reverted to include navigation property and conventional foreign key&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Lodging&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; LodgingId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Owner { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; IsResort { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;decimal&lt;/span&gt; MilesFromNearestAirport { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; DestinationId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Destination Destination { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; List&amp;lt;InternetSpecial&amp;gt; InternetSpecials { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PrimaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person SecondaryContact { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Working with One-to-One Relationships&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用一对一关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;There is one type of relationship that Code First will always require configuration for: one-to-one relationships. When you define a one-to-one relationship in your model, you use a reference navigation property in each class. If you have a reference and a collection, Code First can infer that the class with the reference is the dependent and should have the foreign key. If you have two collections, Code First knows it's many-to-many and the foreign keys go in a separate join table. However, when Code First just sees two references, it can't work out which class should have the foreign key.&lt;/p&gt;&lt;p&gt;Let's add a new PersonPhoto class to contain a photo and a caption for the people in the Person class. Since the photo will be for a specific person, we'll use PersonId as the key property. And since that is not a conventional key property, it needs to be configured as such with the Key Data Annotation (Example 4-20).&lt;/p&gt;&lt;p&gt;还有一种一种关系Code First需要总是进行配置，就是一对一关系。当你在模型中定义一对一关系，你需要在每个类中都要使用引用导航。如果你有一个引用和一个集合，Code First就会将引用视为依赖类，推测应该有一个外键。如果有两个集合，Code First视为多对多关系，将外键放在一个单独的内联表中。但是，Code First看到两个引用时，它无法识别哪个类应该有一个外键。&lt;/p&gt;&lt;p&gt;我们添加一个新的PersonPhoto类，包含一个针对属于Person类中的people的photo和caption属性。由于photo将会指定给特定的person，我们使用PersonId作为键属性。并有没有一个默认的键属性，需要如下所示的Data Annotations配置（代码4-20）：&lt;/p&gt;&lt;p&gt;Example 4-20. The PersonPhoto class&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.ComponentModel.DataAnnotations; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; Model &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersonPhoto&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[Key] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; PersonId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;byte&lt;/span&gt;[] Photo { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Caption { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PhotoOf { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Let's also add a Photo property to the Person class, so that we can navigate both directions:&lt;/p&gt;&lt;p&gt;我们在Person中也添加一个Photo属性，这样可以在两端都可以导航。&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; color: blue; font-size: 9pt;"&gt;public&lt;/span&gt; PersonPhoto Photo &lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Remember that Code First can't determine which class is the dependent in these situations. When it attempts to build the model, an exception is thrown, telling you that it needs more information:&lt;/p&gt;&lt;p&gt;记住在这种情况下Code First无法确认哪个类是依赖类。当其尝试构建模型时，就会抛出一个异常，告知你它需要更多信息：&lt;/p&gt;&lt;code&gt;Unable to determine the principal end of an association between the types 'Model.PersonPhoto' and 'Model.Person'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations. &lt;/code&gt;&lt;code&gt;无法确认在类型'Model.PersonPhoto'和'Model.Person'之间联系的主端。这种联系的主端必须使用Fluent API或DA进行显示配置。 &lt;/code&gt;&lt;p&gt;This problem is most easily solved by using a ForeignKey annotation on the dependent class to identify that it contains the foreign key. When configuring one-to-one relationships, Entity Framework requires that the primary key of the dependent also be the foreign key. In our case PersonPhoto is the dependent and its key, PersonPhoto.PersonId, should also be the foreign key. Go ahead and add in the ForeignKey annotation to the PersonPhoto.PersonId property, as shown in Example 4-21. Remember to specify the navigation property for the relationship when adding the ForeignKey annotation.&lt;/p&gt;&lt;p&gt;这个问题可以很容易地使用ForeignKey特性标记来解决，将标记放在依赖类上指出其包含外键。当配置一对一关系时，EF框架需要依赖类的主键也应是外键。在我们的案例中，PersonPhoto是依赖类，而其键，PersonPhoto.PersonId，也应是一个外键。我们将ForeignKey标记加在PersonPhoto.PersonId属性上，如代码4-21，记住在加入ForeignKey时要为关系指定导航属性。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Example 4-21. Adding the ForeignKey annotation&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersonPhoto&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[Key] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;[ForeignKey(&lt;span style="color: #a31515;"&gt;"PhotoOf"&lt;/span&gt;)] &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; PersonId { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;byte&lt;/span&gt;[] Photo { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Caption { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; Person PhotoOf { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Running the application again will successfully create the new database table, although you'll see that Entity Framework didn't deal well with pluralizing the word "Photo." We'll clean that up in Chapter 5, when you learn how to specify table names. More importantly, notice that PersonId is now both a PK and an FK. And if you look at the PersonPhoto_PhotoOf foreign key constraint details, you can see that it shows the People.PersonId is the primary table/column in the relationship and PersonPhotoes.PersonId is the foreign key table/column (Figure 4-14). This matches our intent.&lt;/p&gt;&lt;p&gt;运行程序会成功创建新数据库标，尽管你会看到EF框架并没有很好地处理单词"Photo",还是将其复数化。第5章你会学习如何为表指定名称。更重要的是，注意到PersonId现在即是PK又是FK。如果你观察PersonPhoto_PhotoOf外键约束细节，你可以看到这里显示People.PersonId在关系中是主表/列，而PersonPhotoes.PersonId是外键表/列（图4-14）：&lt;/p&gt;&lt;p&gt;&lt;img src="http://images.cnblogs.com/cnblogs_com/qouoww/201201/201201031751279657.png" alt="" /&gt;&lt;/p&gt;&lt;p&gt;Earlier in this chapter, we also saw that you could place the ForeignKey annotation on the navigation property and specify the name of the foreign key property (in our case, that is PersonId). Since both classes contain a PersonId property, Code First still won't be able to work out which class contains the foreign key. So you can't employ the configuration in that way for this scenario.&lt;/p&gt;&lt;p&gt;Of course, there is also a way to configure this in the Fluent API. Let's assume for the moment that the relationship is one-to-zero-or-one, meaning a PersonPhoto must have a Person but a Person isn't required to have a PersonPhoto. We can use the HasRequired and WithOptional combination to specify this:&lt;/p&gt;&lt;p&gt;在本章前面，我我们看到你可以将ForeignKey标记放在导航属性上，也可以指定外键属性的名称（在本例中，就是PersonId）.由于两个类都包含PersonId属性，Code First仍不能确认哪个类包含外键，因此你不能用这样的方式来为此种场景配置。&lt;/p&gt;&lt;p&gt;当然，我们也可以Fluent API来进行配置。我们假定这时的关系是一对零或一对一，也就是PersonPhoto必须有一个Person对应而一个Person不必一定有一个PersonPhoto对应。我们使用HasRequired和WithOptinal联合使用来指定这种情况：&lt;/p&gt;&lt;p&gt;modelBuilder.Entity&amp;lt;PersonPhoto&amp;gt;()&lt;/p&gt;&lt;p&gt;.HasRequired(p =&amp;gt; p.PhotoOf)&lt;/p&gt;&lt;p&gt;.WithOptional(p =&amp;gt; p.Photo);&lt;/p&gt;&lt;p&gt;That's actually enough for Code First to work out that PersonPhoto is the dependent. Based on the multiplicity we specified, it only makes sense for Person to be the principal and PersonPhoto to be the dependent, since a Person can exist without a PersonPhoto but a PersonPhoto must have a Person.&lt;/p&gt;&lt;p&gt;Notice that you didn't need to use HasForeignKey to specify that PersonPhoto.PersonId is the foreign key. This is because of Entity Framework's requirement that the primary key of the dependent be used as the foreign key. Since there is no choice, Code First will just infer this for you. In fact, the Fluent API won't let you use HasForeignKey. In IntelliSense, the method simply isn't available after combining HasRequired and WithOptional.&lt;/p&gt;&lt;p&gt;这足以让Code First将PersonPhoto视作依赖类。我们想要将Person类作为主类而PersonPhoto辅助类，因为一个Person可以存在没有PersonPhoto的情况，但是一个PersonPhoto必须有一个Person.&lt;/p&gt;&lt;p&gt;注意你没有必要使用HasForeignKey来指定PersonPhot.PersonId作为外键。这是因为EF框架可以直接将依赖项的主键作为外键使用。由于没有选择，Code First会将这种唯一情况推断出来。事实上，Fluent API也不会让你使用HasForeignKey，在HasRequired和WithOptional方法后的智能感知里该方法根本不可用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Configuring One-to-One Relationships When Both Ends Are Required&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;当两端都是必须项是配置一对一关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Now let's tell Code First that a Person must have a PersonPhoto (i.e., it's required). With Data Annotations, you can use the same Required data annotation that we used earlier on Destination.Name and Lodging.Name. You can use Required on any type of property,not just primitive types:&lt;/p&gt;&lt;p&gt;现在我们来告诉Code First一个Person必须有一个PersonPhoto（即也是必须项）。使Data Annotations，你可以将Rrequired标记放在任何类型的属性上来实现（不一定非是原生类型）：&lt;/p&gt;&lt;p&gt;[Required]&lt;/p&gt;&lt;p&gt;public PersonPhoto Photo { get; set; }&lt;/p&gt;&lt;p&gt;Now update the Main method to call the InsertPerson method you defined back in Chapter 3 and run the application again. An exception will be thrown when SaveChanges is called. In the exception, Entity Framework's Validation API reports that the validation for the required PersonPhoto failed.&lt;/p&gt;&lt;p&gt;现在更新Main方法来调用InserPerson方法（见第3章），运行程序。在运行SaveChanges时会抛出异常，EF框架的验证API报告对必须项PersonPhoto的验证失败。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Ensuring that the sample code honors the required Photo&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;确保使用代码满足必须要求&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;If you want to leave the Photo property as Required and avoid the validation errors, you can modify the InsertPerson and UpdatePerson methods so that they add data into the Photo field. For the sake of keeping the code simple, we'll just stuff a single byte into the Photo's byte array rather than worrying about supplying an actual photo.&lt;/p&gt;&lt;p&gt;In the InsertPerson method, modify the line of code that instantiates a new Person object to add the Photo property, as shown in Example 4-22.&lt;/p&gt;&lt;p&gt;如果你想让Photo属性为必须项避免验证错误，你可以修改InsertPerson和UpdatePerson方法以便使用它们可针数据添加到Photo字段中。为了保持代码的简洁，我们只填充一个单一的字节到图片的byte数组里而不是使用实际的图片。&lt;/p&gt;&lt;p&gt;在InsertPerson方法里，修改代码实例化一个新的Person对象添加Photo属性，如代码4-22：&lt;/p&gt;&lt;p&gt;Example 4-22. Modifying the InsertPerson method to add a Photo to the new Person&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var person = &lt;span style="color: blue;"&gt;new&lt;/span&gt; Person &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;FirstName = &lt;span style="color: #a31515;"&gt;"Rowan"&lt;/span&gt;, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;LastName = &lt;span style="color: #a31515;"&gt;"Miller"&lt;/span&gt;, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;SocialSecurityNumber = 12345678, &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;Photo = &lt;span style="color: blue;"&gt;new&lt;/span&gt; PersonPhoto { Photo = &lt;span style="color: blue;"&gt;new&lt;/span&gt; Byte[] { 0 } } &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;}; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;In the UpdatePerson method, we'll add some code to ensure that any Person data you've already added before we created the Photo class gets a Photo at the same time that you update. Modify the UpdatePerson method as shown in Example 4-23 so that it allocates a new PersonPhoto when it tries to update a person without a photo&lt;/p&gt;&lt;p&gt;在UpdatePerson方法中，我们添加了一些代码来保证任何已添加的Person数据都会在更新时同时获得一个Photo。修改UpdatePerson方法见代码4-23：&lt;/p&gt;&lt;p&gt;Example 4-23. Modification to UpdatePerson to ensure existing Person data has a Photo&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; UpdatePerson() &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (var context = &lt;span style="color: blue;"&gt;new&lt;/span&gt; BreakAwayContext()) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;var person = context.People.Include(&lt;span style="color: #a31515;"&gt;"Photo"&lt;/span&gt;).FirstOrDefault(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;person.FirstName = &lt;span style="color: #a31515;"&gt;"Rowena"&lt;/span&gt;; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (person.Photo == &lt;span style="color: blue;"&gt;null&lt;/span&gt;) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;{ &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;person.Photo = &lt;span style="color: blue;"&gt;new&lt;/span&gt; PersonPhoto { Photo = &lt;span style="color: blue;"&gt;new&lt;/span&gt; Byte[] { 0 } }; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;context.SaveChanges(); &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: 新宋体; font-size: 9pt;"&gt;} &lt;/span&gt;&lt;/p&gt;&lt;p&gt;The updated method will use Include to also retrieve the Person's Photo when fetching the data from the database. We then check if the Person has a Photo and add a new one if they do not. Now the Photo requirement in the Person class will be fulfilled any time you execute the InsertPerson and UpdatePerson methods.&lt;/p&gt;&lt;p&gt;更新方法使用Include方法来获取数据库中Person的图片。然后检查Person对象是否有Photo数据，如果没有就添加一个新的。现在Person类中的Photo必须项得到满足，你可以在任何时候成功执行InsertPerson和UpdatePerson方法。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Configuring one-to-one with the Fluent API&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;使用Fluent API配置一对一关系&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Not surprisingly, you can also configure the same relationship with the Fluent API. But you'll need to let Code First know which class is the principal and which is the dependent. If both ends are required, this can't simply be implied from the multiplicity.&lt;/p&gt;&lt;p&gt;You might expect to call HasRequired followed by WithRequired. However, if you start with HasRequired, you will have the additional options of WithRequiredPrincipal and WithRequiredDependent in the place of WithRequired. These methods take into account the entity that you are configuring; that is, the entity that you selected in model Builder.Entity or the entity that your EntityTypeConfiguration class is for. Selecting WithRequiredPrincipal will make the entity that you are configuring the principal, meaning it contains the primary key of the relationship. Selecting WithRequiredDependent will make the entity that you are configuring the dependent, meaning it will have the foreign key of the relationship.&lt;/p&gt;&lt;p&gt;毫无疑问，也可以使用Fluent API来配置同样的关系。但首先需要让Code First知道哪个类为主哪个类为辅。如果两端均为必须项，不能简单地从多重关系上推测出来。&lt;/p&gt;&lt;p&gt;你可以期待调用HasRequired跟随在WidthRequired。但是如果你开始开HasRequired，你会在WithReuired的位置有两个附加选择：WithRequiredPrincipal 和WithRequiredDependent。这些方法将你要配置的实体考虑了进去（就是你选择的基于模型构建器或者EntityTypeConfiguration类建立的实体）。选择WithRequiredPrincipal将会使实体配置为主类，意味着该类包含有关系的主键。选择WithRequiredDependent会使实体配置为辅助类，意味着该类包含有关系的外键。&lt;/p&gt;&lt;p&gt;Assuming you are configuring PersonPhoto, which you want to be the dependent, you would use the following configuration:&lt;/p&gt;&lt;p&gt;假设你想将PersonPhoto配置为辅助类，你应该使用下列配置代码：&lt;/p&gt;&lt;p&gt;modelBuilder.Entity&amp;lt;PersonPhoto&amp;gt;()&lt;/p&gt;&lt;p&gt;.HasRequired(p =&amp;gt; p.PhotoOf)&lt;/p&gt;&lt;p&gt;.WithRequiredDependent(p =&amp;gt; p.Photo());&lt;/p&gt;&lt;p&gt;Configuring a one-to-one relationship where both ends are optional works exactly the same, except you start with HasOptional and select either WithOptionalPrincipal or WithOptionalDependent.&lt;/p&gt;&lt;p&gt;配置两端都是可选的一对一的关系方法是类似的，除了你应该开始于HasOptional外还应该选择是WithOptionalPrincipal 还是 WithOptionalDependent。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;小结&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In this chapter, you've seen that Code First has a lot of intelligence about relationships. Code First conventions are able to discover relationships of any multiplicity with or without a provided foreign key. But there are many scenarios where your intentions don't coincide with Code First conventions. You've learned many ways to "fix" the model by configuring with Data Annotations and the Fluent API. You should have a good understanding of how to work with relationships in the Fluent API based on its Has/With pattern.&lt;/p&gt;&lt;p&gt;In the next chapter, we'll look at another set of mappings in Code First that are all about how your classes map to the database, including how to map a variety of inheritance hierarchies.&lt;/p&gt;&lt;p&gt;在本章，你已经看到Code First在处理关系上很智能。Code First的默认规则能够发现任何多样性的关系，并适时提供外键配置。但也有一些场景你不想完全遵循默认规则。你也学习了如何使用Data Annotations和Fluent API来定制模型。你应该已经很好地理解了如何在在Fluent API中使用基于Has/With的语句来处理关系。&lt;/p&gt;&lt;p&gt;在下一章，我们来看看Code First的另一套映射，就是类如何映射到数据库，包括如何映射到各种继承架构等。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2363472.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2012/02/22/ef.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2011/12/15/2289030.html</id><title type="text">Associations in EF Code First: Part 1 – Introduction and Basic Concepts</title><summary type="text">Earlier this month the data team shipped the Release Candidate of EF 4.1. The most exciting feature of EF 4.1 is Code First, a new development pattern for EF which provides a really elegant and powerful code-centric way to work with data as well as an alternative to the existing Database First and M</summary><published>2011-12-15T08:03:00Z</published><updated>2011-12-15T08:03:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2011/12/15/2289030.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2011/12/15/2289030.html"/><content type="html">&lt;p&gt;Earlier this month the data team shipped the &lt;a href="http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-release-candidate-available.aspx" target="_blank"&gt;Release Candidate&lt;/a&gt; of EF 4.1. The most exciting feature of EF 4.1 is &lt;em&gt;Code First&lt;/em&gt;, a new development pattern for EF which provides a really elegant and powerful code-centric way to work with data as well as an alternative to the existing &lt;em&gt;Database First&lt;/em&gt; and &lt;em&gt;Model First&lt;/em&gt; patterns. Code First is designed based on &lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration" target="_blank"&gt;Convention over Configuration&lt;/a&gt; paradigm and focused around defining your model using C#/VB.NET classes, these classes can then be mapped to an existing database or be used to generate a database schema. Additional configuration can be supplied using Data Annotations or via a fluent API. &lt;br /&gt;&lt;br /&gt;I&amp;rsquo;m a big fan of the EF Code First approach, and wrote several blog posts about it based on its CTP5 build:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2010/12/11/entity-association-mapping-with-code-first-part-1-one-to-one-associations.aspx" target="_blank"&gt;Associations in EF Code First CTP5: Part 1 &amp;ndash; Complex Types&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2010/12/19/entity-association-mapping-with-code-first-one-to-one-shared-primary-key-associations.aspx" target="_blank"&gt;Associations in EF Code First CTP5: Part 2 &amp;ndash; Shared Primary Key Associations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/01/23/associations-in-ef-code-first-ctp5-part-3-one-to-one-foreign-key-associations.aspx" target="_blank"&gt;Associations in EF Code First CTP5: Part 3 &amp;ndash; One-to-One Foreign Key Associations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx" target="_blank"&gt;Inheritance with EF Code First CTP5: Part 1 &amp;ndash; Table per Hierarchy (TPH) &lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2010/12/28/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt.aspx" target="_blank"&gt;Inheritance with EF Code First CTP5: Part 2 &amp;ndash; Table per Type (TPT)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines.aspx" target="_blank"&gt;Inheritance with EF Code First CTP5: Part 3 &amp;ndash; Table per Concrete Type (TPC)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Compare to CTP5, EF 4.1 release is more about bug fixing and bringing it to a go-live quality level than anything else. Pretty much all of the API that has been introduced in CTP5 is still exactly the same (except very few changes including renaming of DbDatabase and ModelBuilder classes as well as consolidation of IsIndependent fluent API method). Therefore, the above blog posts are still usable and can (hopefully) help you in your Code First development. Having said that, I decided to complete my Code First articles by starting a whole new series instead of doing post maintenance on the current CTP5 ones.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;A Note For Those Who are New to EF and Code-First&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;If you choose to learn EF you've chosen well. If you choose to learn EF with Code First you've done even better. To get started, you can find an EF 4.1 Code First walkthrough by ADO.NET team &lt;a href="http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx" target="_blank"&gt;here&lt;/a&gt;. In this series, I assume you already setup your machine to do Code First development and also that you are familiar with Code First fundamentals and basic concepts.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Code First And Associations&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I will start my EF 4.1 Code First articles by a series on entity association mappings. You will see that when it comes to associations, Code First brings ultimate power and flexibility. This series will come in several parts including:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Part 1 &amp;ndash; Introduction and Basic Concepts&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/03/28/associations-in-ef-4-1-code-first-part-2-complex-types.aspx" target="_blank"&gt;Part 2 &amp;ndash; Complex Types&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/04/14/associations-in-ef-4-1-code-first-part-3-shared-primary-key-associations.aspx" target="_blank"&gt;Part 3 &amp;ndash; Shared Primary Key Associations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/04/24/associations-in-ef-4-1-code-first-part-4-table-splitting.aspx" target="_blank"&gt;Part 4 &amp;ndash; Table Splitting&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx" target="_blank"&gt;Part 5 &amp;ndash; One-to-One Foreign Key Associations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/manavi/archive/2011/05/17/associations-in-ef-4-1-code-first-part-6-many-valued-associations.aspx" target="_blank"&gt;Part 6 &amp;ndash; Many-valued Associations&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Why Starting with Association Mappings?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;From my experience with the EF user community, I know that the first thing many developers try to do when they begin using EF (specially when having a Code First approach) is a mapping of a parent/children relationship. This is usually the first time you encounter collections. It&amp;rsquo;s also the first time you have to think about the differences between entities and value types, or the type of relationships between your entities. Managing the associations between classes and the relationships between tables is at the heart of ORM. Most of the difficult problems involved in implementing an ORM solution relate to association management. &lt;br /&gt;&lt;br /&gt;In order to build a solid foundation for our discussion, we will start by learning about some of the core concepts around the relationship mapping and will leave the discussion for each type of entity associations to the next posts in this series.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What is Mapping?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Mapping&lt;/em&gt;is the act of determining how objects and their relationships are persisted in permanent data storage, in our case, relational databases.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What is Relationship Mapping?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;A mapping that describes how to persist a relationship (association, aggregation, or composition) between two or more objects.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Types of Relationships&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;There are two categories of object relationships that we need to be concerned with when mapping associations. The first category is based on &lt;em&gt;multiplicity&lt;/em&gt;and it includes three types:&lt;/p&gt;&lt;ul&gt;&lt;li style="padding-top: 0px;"&gt;&lt;strong&gt;One-to-one relationships:&lt;/strong&gt; This is a relationship where the maximums of each of its multiplicities is one.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;One-to-many relationships:&lt;/strong&gt; Also known as a many-to-one relationship, this occurs when the maximum of one multiplicity is one and the other is greater than one.&lt;/li&gt;&lt;li style="padding-bottom: 5px;"&gt;&lt;strong&gt;Many-to-many relationships:&lt;/strong&gt; This is a relationship where the maximum of both multiplicities is greater than one.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The second category is based on &lt;em&gt;directionality&lt;/em&gt;and it contains two types:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Uni-directional relationships: &lt;/strong&gt;when an object knows about the object(s) it is related to but the other object(s) do not know of the original object. To put this in EF terminology, when a navigation property exists only on one of the association ends and not on the both.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Bi-directional relationships:&lt;/strong&gt; When the objects on both end of the relationship know of each other (i.e. a navigation property defined on both ends).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;How Object Relationships are Implemented in POCO Object Models?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;When the multiplicity is one (e.g. 0..1 or 1) the relationship is implemented by defining a &lt;em&gt;navigation property&lt;/em&gt; that reference the other object (e.g. an Address property on User class). When the multiplicity is many (e.g. 0..*, 1..*) the relationship is implemented via an &lt;a href="http://msdn.microsoft.com/en-us/library/system.collections.icollection.aspx" target="_blank"&gt;ICollection&lt;/a&gt;of the type of other object.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How Relational Database Relationships are Implemented?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Relationships in relational databases are maintained through the use of &lt;em&gt;Foreign Keys&lt;/em&gt;. A foreign key is a data attribute(s) that appears in one table and must be the primary key or other candidate key in another table. With a one-to-one relationship the foreign key needs to be implemented by one of the tables. To implement a one-to-many relationship we implement a foreign key from the &amp;ldquo;one table&amp;rdquo; to the &amp;ldquo;many table&amp;rdquo;. We could also choose to implement a one-to-many relationship via an &lt;em&gt;associative table&lt;/em&gt; (aka &lt;em&gt;Join table&lt;/em&gt;), effectively making it a many-to-many relationship.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2289030.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2011/12/15/2289030.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2011/11/22/2259116.html</id><title type="text">asp.net mvc 身份验证中返回绝对路径的ReturnUrl</title><summary type="text">在asp.net mvc进行身份验证只用在需要验证的Action或者Controller上标记一个[authorization]即可，如果用户没有登陆，此时将返回的ActionResult是HttpUnauthorizedResultCode highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--&gt;publicclassHttpUnauthorizedResult:ActionResult{publicoverridevoidExecuteResult(Con</summary><published>2011-11-22T09:29:00Z</published><updated>2011-11-22T09:29:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2011/11/22/2259116.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2011/11/22/2259116.html"/><content type="html">&lt;div id="cnblogs_post_body"&gt;&lt;p&gt;在asp.net mvc进行身份验证只用在需要验证的Action或者Controller上标记一个[authorization]即可，如果用户没有登陆，此时将返回的ActionResult是HttpUnauthorizedResult&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;HttpUnauthorizedResult&amp;nbsp;:&amp;nbsp;ActionResult&amp;nbsp;{&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;override&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ExecuteResult(ControllerContext&amp;nbsp;context)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;(context&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ArgumentNullException(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;context&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;nbsp;401&amp;nbsp;is&amp;nbsp;the&amp;nbsp;HTTP&amp;nbsp;status&amp;nbsp;code&amp;nbsp;for&amp;nbsp;unauthorized&amp;nbsp;access&amp;nbsp;-&amp;nbsp;setting&amp;nbsp;this&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;nbsp;will&amp;nbsp;cause&amp;nbsp;the&amp;nbsp;active&amp;nbsp;authentication&amp;nbsp;module&amp;nbsp;to&amp;nbsp;execute&amp;nbsp;its&amp;nbsp;default&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;nbsp;unauthorized&amp;nbsp;handler&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;context.HttpContext.Response.StatusCode&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800080;"&gt;401&lt;/span&gt;&lt;span style="color: #000000;"&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;从HttpUnauthorizedResult的源码可以看出，HttpUnauthorizedResult的执行很简单，就是设置当前的HttpContext.Response的状态码为401，这样就回激活authentication module&amp;nbsp;执行它默认的 unauthorized handler，也就是跳转到登陆页面的，但是默认的跳转ReturnURL 参数的地址是相对的，这在不同域名下实现单点登录时显然是不能满足我的需要的。&lt;/p&gt;&lt;p&gt;解决的办法就是继承AuthorizeAttribute这个特性，重写OnAuthorization方法&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ClientAuthorizeAttribute&amp;nbsp;:&amp;nbsp;AuthorizeAttribute&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;override&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;OnAuthorization(AuthorizationContext&amp;nbsp;filterContext)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;base&lt;/span&gt;&lt;span style="color: #000000;"&gt;.OnAuthorization(filterContext);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;(filterContext.Result&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;is&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;HttpUnauthorizedResult)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filterContext.Result&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;RedirectResult(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;.Concat(FormsAuthentication.LoginUrl,&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;?ReturnUrl=&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filterContext.HttpContext.Server.UrlEncode(filterContext.HttpContext.Request.Url.AbsoluteUri)));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;使用的时候在需要身份验证的Action或者Controller上标记上我们自定义的这个ClientAuthorizeAttribute就行了。&lt;/p&gt;&lt;p&gt;例如：&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;!--&lt;br /&gt;&lt;br /&gt;Code highlighting produced by Actipro CodeHighlighter (freeware)&lt;br /&gt;http://www.CodeHighlighter.com/&lt;br /&gt;&lt;br /&gt;--&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[HandleError]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[ClientAuthorize(Roles&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Admin&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;)]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;AdminController&amp;nbsp;:&amp;nbsp;Controller&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;nbsp;GET:&amp;nbsp;/Admin/&lt;/span&gt;&lt;span style="color: #008000;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;ActionResult&amp;nbsp;Index()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;nbsp;View();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2259116.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2011/11/22/2259116.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2011/10/13/2209896.html</id><title type="text">在asp.net mvc3中编译视图文件</title><summary type="text">Why compiled views?First of all I prefer VS.NET to compile the cshtml code at build time because it will notice syntax errors like on any .cs file. Syntax errors are most important when I have to do a quick check-in of all my sources to repository and I need to make sure I will not crash the next te</summary><published>2011-10-13T02:47:00Z</published><updated>2011-10-13T02:47:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2011/10/13/2209896.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2011/10/13/2209896.html"/><content type="html">&lt;p&gt;&lt;strong&gt;Why compiled views?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;First of all I prefer VS.NET to compile the cshtml code at build time because it will notice syntax errors like on any .cs file. Syntax errors are most important when I have to do a quick check-in of all my sources to repository and I need to make sure I will not crash the next test build. On a default project the views are parsed and compiled at runtime when you fist navigate to the url with your browser, in other word the load time of an action will take longer because of the compiler. I prefer to wait a little longer for Visual Studio to check and compile my views then to wait for each one while debugging.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How to&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Fist step is to edit the .csproj file and set the MvcBuildViews value to true. This setting was available since MVC 1 and it works on &lt;em&gt;aspx&lt;/em&gt;&amp;nbsp; and &lt;em&gt;cshtml&lt;/em&gt; as well.&amp;nbsp; There are lots of articles on the web about this, all you have to do is unload or close the mvc project in vs.net, edit the .cspoj file with vs.net or any other xml editor, locate&lt;em&gt; &amp;lt;MvcBuildViews&amp;gt;&lt;/em&gt;&amp;nbsp; and change the value to &lt;em&gt;true&lt;/em&gt;.&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:5db67940-396b-4a7d-8d5d-0745c0a72202" class="wlWriterEditableSmartContent"&gt;&lt;div class="le-pavsc-container"&gt;&lt;div class="le-pavsc-titleblock"&gt;.csproj&lt;/div&gt;&lt;div style="padding-bottom: 2px; background-color: #ffffff; padding-left: 5px; padding-right: 5px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;MvcBuildViews&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;true&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;MvcBuildViews&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;When you&amp;#8217;ll fist build the project if you have a .edmx file inside a MsBuild error will pop-up about EntityDesignerBuildProvider assembly. In order to fix this error open your project web.config and tell MsBuild that it should skip the edmx file from compilation:&lt;/p&gt;&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9ce6104f-a9aa-4a17-a79f-3a39532ebf7c:6f88a2cc-f572-4b90-8df3-f5fd4aeb4d4e" class="wlWriterEditableSmartContent"&gt;&lt;div class="le-pavsc-container"&gt;&lt;div class="le-pavsc-titleblock"&gt;Web.config&lt;/div&gt;&lt;div style="padding-bottom: 2px; background-color: #ffffff; padding-left: 5px; padding-right: 5px; overflow: auto; padding-top: 2px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;compilation&lt;/span&gt;&lt;span style="color: #0000ff"&gt; &lt;/span&gt;&lt;span style="color: #ff0000"&gt;debug&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&lt;/span&gt;"&lt;span style="color: #0000ff"&gt;true&lt;/span&gt;"&lt;span style="color: #0000ff"&gt; &lt;/span&gt;&lt;span style="color: #ff0000"&gt;targetFramework&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&lt;/span&gt;"&lt;span style="color: #0000ff"&gt;4.0&lt;/span&gt;"&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;buildProviders&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;remove&lt;/span&gt;&lt;span style="color: #0000ff"&gt; &lt;/span&gt;&lt;span style="color: #ff0000"&gt;extension&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&lt;/span&gt;"&lt;span style="color: #0000ff"&gt;.edmx&lt;/span&gt;"&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;buildProviders&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;For more information on this topic check out these blog posts from &lt;a href="http://www.dotnetcurry.com/ShowArticle.aspx?ID=698" target="_blank" modo="false" jquery161033292522075717245="4"&gt;Malcolm Sheridan&lt;/a&gt; and&amp;nbsp; &lt;a href="http://odetocode.com/blogs/scott/archive/2011/02/16/notes-on-building-razor-views.aspx#" target="_blank" jquery161033292522075717245="5"&gt;K. Scott Allen&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Some times Visual Studio will fail to build with an error regarding IIS, in order to fix it, delete the content of the Obj/Debug folder or run the &amp;#8220;Clean&amp;#8221; command on your project.&lt;/p&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2209896.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2011/10/13/2209896.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/hyl8218/archive/2011/10/11/2206929.html</id><title type="text">如何管理Entity Framework中得事务</title><summary type="text">http://msdn.microsoft.com/en-us/library/bb738523.aspxThis topic provides an example of how to define a transaction that coordinates making changes to objects in an object context with other external operations. For more information, see Managing Connections and Transactions. The example in this t...</summary><published>2011-10-11T02:39:00Z</published><updated>2011-10-11T02:39:00Z</updated><author><name>ido</name><uri>http://www.cnblogs.com/hyl8218/</uri></author><link rel="alternate" href="http://www.cnblogs.com/hyl8218/archive/2011/10/11/2206929.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/hyl8218/archive/2011/10/11/2206929.html"/><content type="html">&lt;div&gt;http://msdn.microsoft.com/en-us/library/bb738523.aspx&lt;/div&gt;&lt;p&gt;&amp;nbsp;This topic provides an example of how to define a transaction that  coordinates making changes to objects in an object context with other external  operations. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb896325.aspx"&gt;Managing  Connections and Transactions&lt;/a&gt;.&lt;/p&gt;&lt;div&gt; &lt;p&gt;The example in this topic is based on the &lt;a href="http://msdn.microsoft.com/en-us/library/bb387147.aspx"&gt;AdventureWorks  Sales Model&lt;/a&gt;. To run the code in this example, you must have already added  the AdventureWorks Sales Model to your project and configured your project to  use the Entity Framework. To do this, complete the procedure in &lt;a href="http://msdn.microsoft.com/en-us/library/bb738677.aspx"&gt;How to: Use the  Entity Data Model Wizard&lt;/a&gt;. You must also have Microsoft Windows Message  Queuing installed.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt; &lt;div id="codeExampleSection"&gt; &lt;p&gt;This example defines a &lt;a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx"&gt;TransactionScope&lt;/a&gt;.  The &lt;strong&gt;TransactionScope&lt;/strong&gt; ensures that changes to objects in the  object context are coordinated with a message queue. The Entity Framework uses  this transaction when it saves changes to the database. When an&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/system.data.updateexception.aspx"&gt;UpdateException&lt;/a&gt;  occurs, the operation is retried up to two times. When the operation succeeds,  the changes in the object context are accepted. For more information, see &lt;a href="http://msdn.microsoft.com/en-us/library/bb896325.aspx"&gt;Managing  Connections and Transactions&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;This example uses a long-running object context, which is disposed after the  transaction succeeds or after all retries have been attempted.&lt;/p&gt; &lt;div xmlns=""&gt; &lt;script&gt;&lt;/script&gt;  &lt;div&gt; &lt;div dir="ltr" codesnippetcontainertabactive=""  codesnippetcontainertabfirst"=""&gt;&lt;a&gt;C#&lt;/a&gt;&lt;/div&gt; &lt;div dir="ltr"  codesnippetcontainertablast"=""&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb738523.aspx"&gt;VB&lt;/a&gt;&lt;/div&gt;&lt;/div&gt; &lt;div&gt; &lt;div&gt; &lt;div&gt;&lt;a style="display: block" title="Copy to clipboard." href="http://msdn.microsoft.com/en-us/library/bb738523.aspx" name="CodeSnippetCopyLink"&gt;Copy&lt;/a&gt; &lt;/div&gt;&lt;/div&gt; &lt;div dir="ltr" id="CodeSnippetContainerCode_ed868d7c-a189-4f43-b431-3df8e6fb86de"&gt; &lt;div style="color: black"&gt;&lt;span style="color: blue"&gt;using&lt;/span&gt; System; &lt;span style="color: blue"&gt;using&lt;/span&gt; System.Linq; &lt;span style="color: blue"&gt;using&lt;/span&gt; System.Data; &lt;span style="color: blue"&gt;using&lt;/span&gt; System.Data.Objects; &lt;span style="color: blue"&gt;using&lt;/span&gt; System.Messaging; &lt;span style="color: blue"&gt;using&lt;/span&gt; System.Transactions;  &lt;span style="color: blue"&gt;namespace&lt;/span&gt; ObjectServicesConceptsCS {     &lt;span style="color: blue"&gt;class&lt;/span&gt; TransactionSample     {         &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; EnlistTransaction()         {             &lt;span style="color: blue"&gt;int&lt;/span&gt; retries = 3;             &lt;span style="color: blue"&gt;string&lt;/span&gt; queueName = &lt;span style="color: #a31515"&gt;@".\Fulfilling"&lt;/span&gt;;              &lt;span style="color: green"&gt;// Define variables that we need to add an item.&lt;/span&gt;             &lt;span style="color: blue"&gt;short&lt;/span&gt; quantity = 2;             &lt;span style="color: blue"&gt;int&lt;/span&gt; productId = 750;             &lt;span style="color: blue"&gt;int&lt;/span&gt; orderId = 43680;              &lt;span style="color: green"&gt;// Define a long-running object context.&lt;/span&gt;             AdventureWorksEntities context                 = &lt;span style="color: blue"&gt;new&lt;/span&gt; AdventureWorksEntities();              &lt;span style="color: blue"&gt;bool&lt;/span&gt; success = &lt;span style="color: blue"&gt;false&lt;/span&gt;;              &lt;span style="color: green"&gt;// Wrap the operation in a retry loop.&lt;/span&gt;             &lt;span style="color: blue"&gt;for&lt;/span&gt; (&lt;span style="color: blue"&gt;int&lt;/span&gt; i = 0; i &amp;lt; retries; i++)             {                 &lt;span style="color: green"&gt;// Define a transaction scope for the operations.&lt;/span&gt;                 &lt;span style="color: blue"&gt;using&lt;/span&gt; (TransactionScope transaction = &lt;span style="color: blue"&gt;new&lt;/span&gt; TransactionScope())                 {                     &lt;span style="color: blue"&gt;try&lt;/span&gt;                     {                         &lt;span style="color: green"&gt;// Define a query that returns a order by order ID.&lt;/span&gt;                         SalesOrderHeader order =                         context.SalesOrderHeaders.Where                         (&lt;span style="color: #a31515"&gt;"it.SalesOrderID = @id"&lt;/span&gt;, &lt;span style="color: blue"&gt;new&lt;/span&gt; ObjectParameter(                          &lt;span style="color: #a31515"&gt;"id"&lt;/span&gt;, orderId)).First();                          &lt;span style="color: green"&gt;// Load items for the order, if not already loaded.&lt;/span&gt;                         &lt;span style="color: blue"&gt;if&lt;/span&gt; (!order.SalesOrderDetails.IsLoaded)                         {                             order.SalesOrderDetails.Load();                         }                          &lt;span style="color: green"&gt;// Load the customer, if not already loaded.&lt;/span&gt;                         &lt;span style="color: blue"&gt;if&lt;/span&gt; (!order.ContactReference.IsLoaded)                         {                             order.ContactReference.Load();                         }                          &lt;span style="color: green"&gt;// Create a new item for an existing order.&lt;/span&gt;                         SalesOrderDetail newItem = SalesOrderDetail.CreateSalesOrderDetail(                             0, 0, quantity, productId, 1, 0, 0, 0, Guid.NewGuid(), DateTime.Today);                          &lt;span style="color: green"&gt;// Add new item to the order.&lt;/span&gt;                         order.SalesOrderDetails.Add(newItem);                          &lt;span style="color: green"&gt;// Save changes pessimistically. This means that changes &lt;/span&gt;                         &lt;span style="color: green"&gt;// must be accepted manually once the transaction succeeds.&lt;/span&gt;                         context.SaveChanges(SaveOptions.DetectChangesBeforeSave);                          &lt;span style="color: green"&gt;// Create the message queue if it does not already exist.&lt;/span&gt;                         &lt;span style="color: blue"&gt;if&lt;/span&gt; (!MessageQueue.Exists(queueName))                         {                             MessageQueue.Create(queueName);                         }                          &lt;span style="color: green"&gt;// Initiate fulfilling order by sending a message.&lt;/span&gt;                         &lt;span style="color: blue"&gt;using&lt;/span&gt; (MessageQueue q = &lt;span style="color: blue"&gt;new&lt;/span&gt; MessageQueue(queueName))                         {                             System.Messaging.Message msg =                                 &lt;span style="color: blue"&gt;new&lt;/span&gt; System.Messaging.Message(String.Format(                                     &lt;span style="color: #a31515"&gt;"&amp;lt;order customerId='{0}'&amp;gt;"&lt;/span&gt; +                                     &lt;span style="color: #a31515"&gt;"&amp;lt;orderLine product='{1}' quantity='{2}' /&amp;gt;"&lt;/span&gt; +                                     &lt;span style="color: #a31515"&gt;"&amp;lt;/order&amp;gt;"&lt;/span&gt;, order.Contact.ContactID,                                 newItem.ProductID, newItem.OrderQty));                              &lt;span style="color: green"&gt;// Send the message to the queue.&lt;/span&gt;                             q.Send(msg);                         }                          &lt;span style="color: green"&gt;// Mark the transaction as complete.&lt;/span&gt;                         transaction.Complete();                         success = &lt;span style="color: blue"&gt;true&lt;/span&gt;;                         &lt;span style="color: blue"&gt;break&lt;/span&gt;;                     }                     &lt;span style="color: blue"&gt;catch&lt;/span&gt; (Exception ex)                     {                         &lt;span style="color: green"&gt;// Handle errors and deadlocks here and retry if needed.&lt;/span&gt;                         &lt;span style="color: green"&gt;// Allow an UpdateException to pass through and &lt;/span&gt;                         &lt;span style="color: green"&gt;// retry, otherwise stop the execution.&lt;/span&gt;                         &lt;span style="color: blue"&gt;if&lt;/span&gt; (ex.GetType() != &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(UpdateException))                         {                             Console.WriteLine(&lt;span style="color: #a31515"&gt;"An error occured. "&lt;/span&gt;                                 + &lt;span style="color: #a31515"&gt;"The operation cannot be retried."&lt;/span&gt;                                 + ex.Message);                             &lt;span style="color: blue"&gt;break&lt;/span&gt;;                         }                         &lt;span style="color: green"&gt;// If we get to this point, the operation will be retried.&lt;/span&gt;                     }                 }             }             &lt;span style="color: blue"&gt;if&lt;/span&gt; (success)             {                 &lt;span style="color: green"&gt;// Reset the context since the operation succeeded.&lt;/span&gt;                 context.AcceptAllChanges();             }             &lt;span style="color: blue"&gt;else&lt;/span&gt;             {                 Console.WriteLine(&lt;span style="color: #a31515"&gt;"The operation could not be completed in "&lt;/span&gt;                     + retries + &lt;span style="color: #a31515"&gt;" tries."&lt;/span&gt;);             }              &lt;span style="color: green"&gt;// Dispose the object context.&lt;/span&gt;             context.Dispose();         }     } }  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/hyl8218/aggbug/2206929.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/hyl8218/archive/2011/10/11/2206929.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
