[{"data":1,"prerenderedAt":926},["ShallowReactive",2],{"navigation":3,"post-\u002Fposts\u002F2015\u002Fentity-framework-code-first-two-foreign-keys-from-same-table":20,"surroundPosts-\u002Fposts\u002F2015\u002Fentity-framework-code-first-two-foreign-keys-from-same-table":913},[4,8,12,16],{"title":5,"path":6,"stem":7},"首页","\u002F","00.index",{"title":9,"path":10,"stem":11},"文章","\u002Fposts","01.posts",{"title":13,"path":14,"stem":15},"动态","\u002Fmoments","02.moments",{"title":17,"path":18,"stem":19},"关于","\u002Fabout","09.about",{"id":21,"title":22,"body":23,"class":895,"cover":895,"coverSize":895,"date":896,"description":29,"draft":897,"extension":898,"hideComments":897,"location":899,"meta":900,"navigation":166,"path":901,"readingTime":902,"seo":907,"sitemap":908,"stem":909,"tags":910,"time":895,"weather":895,"__hash__":912},"posts\u002Fposts\u002F2015\u002F20150317.entity-framework-code-first-two-foreign-keys-from-same-table.md","Entity Framework Code First 两个字段关联到同一张表",{"type":24,"value":25,"toc":893},"minimark",[26,30,34,37,40,506,694,697,882,889],[27,28,29],"p",{},"之前也遇到过类似的问题，属于 Code First 中稍微复杂点的关系处理，现将解决方法记录下来。",[31,32,33],"h4",{"id":33},"场景",[27,35,36],{},"某网上书城欲推出书券功能，书券购买之后，会有一个唯一的 Id，可用来直接兑换某本书。书券可以自己兑换，也可以将 ID 送给朋友来兑换。现在我们需要将书券的购买者和兑换者都记录下来。",[31,38,39],{"id":39},"类的设计和注意事项",[41,42,47],"pre",{"className":43,"code":44,"language":45,"meta":46,"style":46},"language-csharp shiki shiki-themes material-theme-lighter github-light github-dark","public class BookCoupon\n{\n    [Key]\n    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]\n    [Index(\"BookCouponIdIndex\")]\n    public Guid BookCouponId { get; set; }\n\n    [Index(\"BookIdIndex\")]\n    public int BookId { get; set; }\n\n    [ForeignKey(\"BookId\")]\n    public virtual Book Book { get; set; }\n\n    [Index(\"BuyUserIdIndex\")]\n    public string BuyUserId { get; set; }\n\n    [ForeignKey(\"BuyUserId\")]\n    public virtual User BuyUser { get; set; }\n\n    [Index(\"RedeemUserIdIndex\")]\n    public string RedeemUserId { get; set; }\n\n    [ForeignKey(\"RedeemUserId\")]\n    public virtual User RedeemUser { get; set; }\n\n    public DateTime BuyTime { get; set; }\n\n    public DateTime RedeemTime { get; set; }\n}\n","csharp","",[48,49,50,67,74,86,110,132,161,168,186,210,215,234,259,264,282,305,310,328,353,358,376,398,403,421,445,450,473,478,500],"code",{"__ignoreMap":46},[51,52,55,59,63],"span",{"class":53,"line":54},"line",1,[51,56,58],{"class":57},"sbsja","public",[51,60,62],{"class":61},"sG8yY"," class",[51,64,66],{"class":65},"sbgvK"," BookCoupon\n",[51,68,70],{"class":53,"line":69},2,[51,71,73],{"class":72},"sP7_E","{\n",[51,75,77,80,83],{"class":53,"line":76},3,[51,78,79],{"class":72},"    [",[51,81,82],{"class":65},"Key",[51,84,85],{"class":72},"]\n",[51,87,89,91,94,97,101,104,107],{"class":53,"line":88},4,[51,90,79],{"class":72},[51,92,93],{"class":65},"DatabaseGeneratedAttribute",[51,95,96],{"class":72},"(",[51,98,100],{"class":99},"su5hD","DatabaseGeneratedOption",[51,102,103],{"class":72},".",[51,105,106],{"class":99},"Identity",[51,108,109],{"class":72},")]\n",[51,111,113,115,118,120,124,128,130],{"class":53,"line":112},5,[51,114,79],{"class":72},[51,116,117],{"class":65},"Index",[51,119,96],{"class":72},[51,121,123],{"class":122},"sjJ54","\"",[51,125,127],{"class":126},"s_sjI","BookCouponIdIndex",[51,129,123],{"class":122},[51,131,109],{"class":72},[51,133,135,138,141,144,147,150,153,156,158],{"class":53,"line":134},6,[51,136,137],{"class":57},"    public",[51,139,140],{"class":65}," Guid",[51,142,143],{"class":65}," BookCouponId",[51,145,146],{"class":72}," {",[51,148,149],{"class":61}," get",[51,151,152],{"class":72},";",[51,154,155],{"class":61}," set",[51,157,152],{"class":72},[51,159,160],{"class":72}," }\n",[51,162,164],{"class":53,"line":163},7,[51,165,167],{"emptyLinePlaceholder":166},true,"\n",[51,169,171,173,175,177,179,182,184],{"class":53,"line":170},8,[51,172,79],{"class":72},[51,174,117],{"class":65},[51,176,96],{"class":72},[51,178,123],{"class":122},[51,180,181],{"class":126},"BookIdIndex",[51,183,123],{"class":122},[51,185,109],{"class":72},[51,187,189,191,195,198,200,202,204,206,208],{"class":53,"line":188},9,[51,190,137],{"class":57},[51,192,194],{"class":193},"smGrS"," int",[51,196,197],{"class":65}," BookId",[51,199,146],{"class":72},[51,201,149],{"class":61},[51,203,152],{"class":72},[51,205,155],{"class":61},[51,207,152],{"class":72},[51,209,160],{"class":72},[51,211,213],{"class":53,"line":212},10,[51,214,167],{"emptyLinePlaceholder":166},[51,216,218,220,223,225,227,230,232],{"class":53,"line":217},11,[51,219,79],{"class":72},[51,221,222],{"class":65},"ForeignKey",[51,224,96],{"class":72},[51,226,123],{"class":122},[51,228,229],{"class":126},"BookId",[51,231,123],{"class":122},[51,233,109],{"class":72},[51,235,237,239,242,245,247,249,251,253,255,257],{"class":53,"line":236},12,[51,238,137],{"class":57},[51,240,241],{"class":57}," virtual",[51,243,244],{"class":65}," Book",[51,246,244],{"class":65},[51,248,146],{"class":72},[51,250,149],{"class":61},[51,252,152],{"class":72},[51,254,155],{"class":61},[51,256,152],{"class":72},[51,258,160],{"class":72},[51,260,262],{"class":53,"line":261},13,[51,263,167],{"emptyLinePlaceholder":166},[51,265,267,269,271,273,275,278,280],{"class":53,"line":266},14,[51,268,79],{"class":72},[51,270,117],{"class":65},[51,272,96],{"class":72},[51,274,123],{"class":122},[51,276,277],{"class":126},"BuyUserIdIndex",[51,279,123],{"class":122},[51,281,109],{"class":72},[51,283,285,287,290,293,295,297,299,301,303],{"class":53,"line":284},15,[51,286,137],{"class":57},[51,288,289],{"class":193}," string",[51,291,292],{"class":65}," BuyUserId",[51,294,146],{"class":72},[51,296,149],{"class":61},[51,298,152],{"class":72},[51,300,155],{"class":61},[51,302,152],{"class":72},[51,304,160],{"class":72},[51,306,308],{"class":53,"line":307},16,[51,309,167],{"emptyLinePlaceholder":166},[51,311,313,315,317,319,321,324,326],{"class":53,"line":312},17,[51,314,79],{"class":72},[51,316,222],{"class":65},[51,318,96],{"class":72},[51,320,123],{"class":122},[51,322,323],{"class":126},"BuyUserId",[51,325,123],{"class":122},[51,327,109],{"class":72},[51,329,331,333,335,338,341,343,345,347,349,351],{"class":53,"line":330},18,[51,332,137],{"class":57},[51,334,241],{"class":57},[51,336,337],{"class":65}," User",[51,339,340],{"class":65}," BuyUser",[51,342,146],{"class":72},[51,344,149],{"class":61},[51,346,152],{"class":72},[51,348,155],{"class":61},[51,350,152],{"class":72},[51,352,160],{"class":72},[51,354,356],{"class":53,"line":355},19,[51,357,167],{"emptyLinePlaceholder":166},[51,359,361,363,365,367,369,372,374],{"class":53,"line":360},20,[51,362,79],{"class":72},[51,364,117],{"class":65},[51,366,96],{"class":72},[51,368,123],{"class":122},[51,370,371],{"class":126},"RedeemUserIdIndex",[51,373,123],{"class":122},[51,375,109],{"class":72},[51,377,379,381,383,386,388,390,392,394,396],{"class":53,"line":378},21,[51,380,137],{"class":57},[51,382,289],{"class":193},[51,384,385],{"class":65}," RedeemUserId",[51,387,146],{"class":72},[51,389,149],{"class":61},[51,391,152],{"class":72},[51,393,155],{"class":61},[51,395,152],{"class":72},[51,397,160],{"class":72},[51,399,401],{"class":53,"line":400},22,[51,402,167],{"emptyLinePlaceholder":166},[51,404,406,408,410,412,414,417,419],{"class":53,"line":405},23,[51,407,79],{"class":72},[51,409,222],{"class":65},[51,411,96],{"class":72},[51,413,123],{"class":122},[51,415,416],{"class":126},"RedeemUserId",[51,418,123],{"class":122},[51,420,109],{"class":72},[51,422,424,426,428,430,433,435,437,439,441,443],{"class":53,"line":423},24,[51,425,137],{"class":57},[51,427,241],{"class":57},[51,429,337],{"class":65},[51,431,432],{"class":65}," RedeemUser",[51,434,146],{"class":72},[51,436,149],{"class":61},[51,438,152],{"class":72},[51,440,155],{"class":61},[51,442,152],{"class":72},[51,444,160],{"class":72},[51,446,448],{"class":53,"line":447},25,[51,449,167],{"emptyLinePlaceholder":166},[51,451,453,455,458,461,463,465,467,469,471],{"class":53,"line":452},26,[51,454,137],{"class":57},[51,456,457],{"class":65}," DateTime",[51,459,460],{"class":65}," BuyTime",[51,462,146],{"class":72},[51,464,149],{"class":61},[51,466,152],{"class":72},[51,468,155],{"class":61},[51,470,152],{"class":72},[51,472,160],{"class":72},[51,474,476],{"class":53,"line":475},27,[51,477,167],{"emptyLinePlaceholder":166},[51,479,481,483,485,488,490,492,494,496,498],{"class":53,"line":480},28,[51,482,137],{"class":57},[51,484,457],{"class":65},[51,486,487],{"class":65}," RedeemTime",[51,489,146],{"class":72},[51,491,149],{"class":61},[51,493,152],{"class":72},[51,495,155],{"class":61},[51,497,152],{"class":72},[51,499,160],{"class":72},[51,501,503],{"class":53,"line":502},29,[51,504,505],{"class":72},"}\n",[41,507,509],{"className":43,"code":508,"language":45,"meta":46,"style":46},"public class User\n{\n    [Key]\n    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]\n    [Index(\"UserIdIndex\")]\n    public Guid UserId { get; set; }\n\n    public string UserName { get; set; }\n\n    public virtual ICollection\u003CBookCoupon> BuyCoupons { get; set; }\n\n    public virtual ICollection\u003CBookCoupon> RedeemCoupons { get; set; }\n\n    ......\n}\n",[48,510,511,520,524,532,548,565,586,590,611,615,648,652,681,685,690],{"__ignoreMap":46},[51,512,513,515,517],{"class":53,"line":54},[51,514,58],{"class":57},[51,516,62],{"class":61},[51,518,519],{"class":65}," User\n",[51,521,522],{"class":53,"line":69},[51,523,73],{"class":72},[51,525,526,528,530],{"class":53,"line":76},[51,527,79],{"class":72},[51,529,82],{"class":65},[51,531,85],{"class":72},[51,533,534,536,538,540,542,544,546],{"class":53,"line":88},[51,535,79],{"class":72},[51,537,93],{"class":65},[51,539,96],{"class":72},[51,541,100],{"class":99},[51,543,103],{"class":72},[51,545,106],{"class":99},[51,547,109],{"class":72},[51,549,550,552,554,556,558,561,563],{"class":53,"line":112},[51,551,79],{"class":72},[51,553,117],{"class":65},[51,555,96],{"class":72},[51,557,123],{"class":122},[51,559,560],{"class":126},"UserIdIndex",[51,562,123],{"class":122},[51,564,109],{"class":72},[51,566,567,569,571,574,576,578,580,582,584],{"class":53,"line":134},[51,568,137],{"class":57},[51,570,140],{"class":65},[51,572,573],{"class":65}," UserId",[51,575,146],{"class":72},[51,577,149],{"class":61},[51,579,152],{"class":72},[51,581,155],{"class":61},[51,583,152],{"class":72},[51,585,160],{"class":72},[51,587,588],{"class":53,"line":163},[51,589,167],{"emptyLinePlaceholder":166},[51,591,592,594,596,599,601,603,605,607,609],{"class":53,"line":170},[51,593,137],{"class":57},[51,595,289],{"class":193},[51,597,598],{"class":65}," UserName",[51,600,146],{"class":72},[51,602,149],{"class":61},[51,604,152],{"class":72},[51,606,155],{"class":61},[51,608,152],{"class":72},[51,610,160],{"class":72},[51,612,613],{"class":53,"line":188},[51,614,167],{"emptyLinePlaceholder":166},[51,616,617,619,621,624,627,630,633,636,638,640,642,644,646],{"class":53,"line":212},[51,618,137],{"class":57},[51,620,241],{"class":57},[51,622,623],{"class":65}," ICollection",[51,625,626],{"class":72},"\u003C",[51,628,629],{"class":65},"BookCoupon",[51,631,632],{"class":72},">",[51,634,635],{"class":65}," BuyCoupons",[51,637,146],{"class":72},[51,639,149],{"class":61},[51,641,152],{"class":72},[51,643,155],{"class":61},[51,645,152],{"class":72},[51,647,160],{"class":72},[51,649,650],{"class":53,"line":217},[51,651,167],{"emptyLinePlaceholder":166},[51,653,654,656,658,660,662,664,666,669,671,673,675,677,679],{"class":53,"line":236},[51,655,137],{"class":57},[51,657,241],{"class":57},[51,659,623],{"class":65},[51,661,626],{"class":72},[51,663,629],{"class":65},[51,665,632],{"class":72},[51,667,668],{"class":65}," RedeemCoupons",[51,670,146],{"class":72},[51,672,149],{"class":61},[51,674,152],{"class":72},[51,676,155],{"class":61},[51,678,152],{"class":72},[51,680,160],{"class":72},[51,682,683],{"class":53,"line":261},[51,684,167],{"emptyLinePlaceholder":166},[51,686,687],{"class":53,"line":266},[51,688,689],{"class":99},"    ......\n",[51,691,692],{"class":53,"line":284},[51,693,505],{"class":72},[27,695,696],{},"另外，在 DbContext 中需要 override OnModelCreating 方法：",[41,698,700],{"className":43,"code":699,"language":45,"meta":46,"style":46},"protected override void OnModelCreating(DbModelBuilder modelBuilder)\n{\n    base.OnModelCreating(modelBuilder);\n    modelBuilder.Entity\u003CApplicationUser>().HasMany(u => u.BuyCoupons).WithRequired(n => n.BuyUser).WillCascadeOnDelete(false);\n    modelBuilder.Entity\u003CApplicationUser>().HasMany(u => u.RedeemCoupons).WithRequired(n => n.RedeemUser).WillCascadeOnDelete(false);\n}\n",[48,701,702,728,732,751,822,878],{"__ignoreMap":46},[51,703,704,707,710,713,717,719,722,725],{"class":53,"line":54},[51,705,706],{"class":57},"protected",[51,708,709],{"class":57}," override",[51,711,712],{"class":193}," void",[51,714,716],{"class":715},"sGLFI"," OnModelCreating",[51,718,96],{"class":72},[51,720,721],{"class":65},"DbModelBuilder",[51,723,724],{"class":65}," modelBuilder",[51,726,727],{"class":72},")\n",[51,729,730],{"class":53,"line":69},[51,731,73],{"class":72},[51,733,734,738,740,743,745,748],{"class":53,"line":76},[51,735,737],{"class":736},"s_hVV","    base",[51,739,103],{"class":72},[51,741,742],{"class":715},"OnModelCreating",[51,744,96],{"class":72},[51,746,747],{"class":99},"modelBuilder",[51,749,750],{"class":72},");\n",[51,752,753,756,758,761,763,766,769,772,774,777,780,783,785,788,791,794,796,799,801,804,806,809,811,814,816,820],{"class":53,"line":88},[51,754,755],{"class":99},"    modelBuilder",[51,757,103],{"class":72},[51,759,760],{"class":715},"Entity",[51,762,626],{"class":72},[51,764,765],{"class":65},"ApplicationUser",[51,767,768],{"class":72},">().",[51,770,771],{"class":715},"HasMany",[51,773,96],{"class":72},[51,775,776],{"class":65},"u",[51,778,779],{"class":193}," =>",[51,781,782],{"class":99}," u",[51,784,103],{"class":72},[51,786,787],{"class":99},"BuyCoupons",[51,789,790],{"class":72},").",[51,792,793],{"class":715},"WithRequired",[51,795,96],{"class":72},[51,797,798],{"class":65},"n",[51,800,779],{"class":193},[51,802,803],{"class":99}," n",[51,805,103],{"class":72},[51,807,808],{"class":99},"BuyUser",[51,810,790],{"class":72},[51,812,813],{"class":715},"WillCascadeOnDelete",[51,815,96],{"class":72},[51,817,819],{"class":818},"syTEX","false",[51,821,750],{"class":72},[51,823,824,826,828,830,832,834,836,838,840,842,844,846,848,851,853,855,857,859,861,863,865,868,870,872,874,876],{"class":53,"line":112},[51,825,755],{"class":99},[51,827,103],{"class":72},[51,829,760],{"class":715},[51,831,626],{"class":72},[51,833,765],{"class":65},[51,835,768],{"class":72},[51,837,771],{"class":715},[51,839,96],{"class":72},[51,841,776],{"class":65},[51,843,779],{"class":193},[51,845,782],{"class":99},[51,847,103],{"class":72},[51,849,850],{"class":99},"RedeemCoupons",[51,852,790],{"class":72},[51,854,793],{"class":715},[51,856,96],{"class":72},[51,858,798],{"class":65},[51,860,779],{"class":193},[51,862,803],{"class":99},[51,864,103],{"class":72},[51,866,867],{"class":99},"RedeemUser",[51,869,790],{"class":72},[51,871,813],{"class":715},[51,873,96],{"class":72},[51,875,819],{"class":818},[51,877,750],{"class":72},[51,879,880],{"class":53,"line":134},[51,881,505],{"class":72},[27,883,884,885,888],{},"注意最后的",[48,886,887],{},".WillCascadeOnDelete(false)","，因为在这样多对多的绑定中，使用级联删除会报错。",[890,891,892],"style",{},"html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sG8yY, html code.shiki .sG8yY{--shiki-light:#E2931D;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":46,"searchDepth":69,"depth":69,"links":894},[],null,"2015-03-17",false,"md","Newegg",{},"\u002Fposts\u002F2015\u002Fentity-framework-code-first-two-foreign-keys-from-same-table",{"text":903,"minutes":904,"time":905,"words":906},"2 min read",1.49,89400,298,{"title":22,"description":29},{"loc":901},"posts\u002F2015\u002F20150317.entity-framework-code-first-two-foreign-keys-from-same-table",[911],"技术","Erw-iLbDHHcgxcCq-ZV9uJ6F7f3-NtOcl_DuUppVbLM",[914,920],{"title":915,"path":916,"stem":917,"date":918,"description":919,"children":-1},"在 Windows Server 2012 (R2) 上显示 “计算机”","\u002Fposts\u002F2015\u002Fshow-computer-on-desktop-in-windows-server","posts\u002F2015\u002F20150318.show-computer-on-desktop-in-windows-server","2015-03-18","Windows Server 2012 (R2)的桌面上，默认是没有“计算机”的，而且桌面上右键也是不会出现个性化的，如下方法可以迅速打开“桌面图标设置”：",{"title":921,"path":922,"stem":923,"date":924,"description":925,"children":-1},"Windows 关屏小工具","\u002Fposts\u002F2015\u002Fwindows-close-monitor-tool","posts\u002F2015\u002F20150306.windows-close-monitor-tool","2015-03-06","有时候下班的时候不想关机，有很多原因，比如有 N 个网页 Tab 开着，有些可能还需要进一步查阅，关了的话从历史里不太好找，又或者，VS 开着调试，没做完，而第二天重新跑一下要很久。于是便有了挂机。可是公然挂机其实并不好，公司有规定下班自觉关机。按显示器按钮太 LOW，高端人士怎么能用这么粗鲁的方法呢！以前我用的是设置 Windows 关屏时间，5 分钟不动鼠标就关闭屏幕。这个坏处是不够及时。有什么办法能立马关闭屏幕呢？于是找到了如下代码：",1777579149956]