我在PM控制台中执行更新数据库时遇到错误。我理解为什么,但鉴于我的需要,我不确定如何最好地克服它。我希望有人能指出我正确的方向。
我有2张桌子,一张用于国家,一张用于州。通常我会使用Id作为主键,但我的客户要求我将关联设为人类可读的。例如,他们希望将其作为“美国”,而不是将其国家/地区的值设为1的用户。他们的状态不是14的值,而是看“CA”或“TX”等等。
我的迁移Configuration.cs包含一个添加国家和州的种子例程。
当我运行Update-Database时,出现以下错误:
运行种子方法。 System.Data.Entity.Infrastructure.DbUpdateException:无法执行 确定'XXX_XXX_XXX.Models.State_Country'的主要结尾 关系。多个添加的实体可以具有相同的主键。 ---> System.Data.Entity.Core.UpdateException:无法确定'XXXX_XXXX_XXXX.Models.State_Country'的主要结尾 关系。多个添加的实体可能具有相同的主键。
我的ViewModel包含:
namespace XXXX_XXXX_XXXX.Models
{
public class Country
{
[Key]
public string CountryCode { get; set; }
public int CountryId { get; set; }
public string CountryName { get; set; }
public virtual ICollection<State> States { get; set; }
}
public class State
{
[Key]
public string StateCode { get; set; }
public int StateId { get; set; }
public string StateName { get; set; }
[ForeignKey("Country")]
public string CountryCode { get; set; }
public virtual Country Country { get; set; }
}
}
我的种子例程如下所示:
protected override void Seed(ProgramDbContext context)
{
// Initialize Countries
context.Countries.AddOrUpdate(c => c.CountryCode,
new Country { CountryId = 1,
CountryName = "United States",
CountryCode = "USA" });
context.Countries.AddOrUpdate(c => c.CountryCode,
new Country { CountryId = 2,
CountryName = "Canada",
CountryCode = "CAN" });
{ ... }
// Initialize States
context.States.AddOrUpdate(c => c.StateId,
new State { StateId = 1,
StateName = "Iowa",
StateCode = "IA",
CountryCode = "USA" });
context.States.AddOrUpdate(c => c.StateId,
new State { StateId = 2,
StateName = "Illinois",
StateCode = "IL",
CountryCode = "USA" });
context.States.AddOrUpdate(c => c.StateId,
new State { StateId = 3,
StateName = "California",
StateCode = "CA",
CountryCode = "USA" });
{ ... }
}
我明白我收到了错误,因为CountryCode不包含每列的唯一值。如果我将CountryId设置为Key并将States的外键更改为CountryId我没有收到错误,但是我似乎必须在Id字段上执行查找以在需要时获取CountryCode。
我也预见到StateCode最终可能会有重复,但目前还没有。
使用ViewModel编码可以在一个表中有2个[Key]属性吗?我无法让它发挥作用。
我是否需要将[Key]
属性放在每个表的Id列上,然后在每次需要更新用户配置文件或创建下拉列表时查找CountryCode和StateCode?顺便说一下,我为CountryCode和StateCode创建了自定义标识字段。
我的国家和州的ViewModel应该如何编码,以便我可以方便地将我的用户配置文件显示为“CA,USA”而不是3,1 - 例如?
修改
@David提议查看我的国家和州下拉列表的查看代码。我使用jQuery填充State下拉列表
我在控制器中填充了Model.Countries:
public IEnumerable<SelectListItem> GetCountryList()
{
var countries = new SelectList(dbLocations.Countries, "CountryCode", "CountryName").ToList();
countries.Insert(0, (new SelectListItem { Text = "Select Country", Value = "-1" }));
countries.Insert(1, (new SelectListItem { Text = "United Sates", Value = "54" }));
countries.Insert(2, (new SelectListItem { Text = "Canada", Value = "13" }));
countries.Insert(3, (new SelectListItem { Text = "Mexico", Value = "12" }));
countries.Insert(4, (new SelectListItem { Text = "Brazil", Value = "36" }));
countries.Insert(5, (new SelectListItem { Text = "------------------------", Value = "-1" }));
IEnumerable<SelectListItem> countrylist =
countries.Select(m => new SelectListItem()
{
Text = m.Text,
Value = m.Value
});
return countrylist;
}
我在视图中使用的示例:
<div class="form-group">
@Html.LabelFor(m => m.CountryId, new { @class = "col-md-3 control-label" })
<div class="col-md-9">
@Html.DropDownListFor(
x => x.CountryId,
new SelectList(Model.Countries, "Value", "Text"),
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.StateId, new { @class = "col-md-3 control-label" })
<div class="col-md-9">
<div id="stateid_select">
<select id="StateId" class="form-control" name="StateId"></select>
</div>
</div>
</div>
jQuery for Country change(检索状态):
<script type="text/javascript">
// Populate State/Province dropdown on Country select
$(function () {
$('#CountryCode').change(function () {
$.getJSON('/Account/StateList/' + $('#CountryCode').val(), function (data) {
var cnt = 0;
var items = '<option>Select a State/Province</option>';
$.each(data, function (i, state) {
items += "<option value='" + state.Value + "'>" + state.Text + "</option>";
cnt = cnt + 1;
});
// Hide SELECT and show TEXT field if no state/provinces to choose from.
// Else show SELECT and hide TEXT field.
if (!cnt == 0) {
$('#stateprovince_select select').html(items).show().attr("disabled", false).removeClass("hide");
$('#stateprovince_text input[type="text"]').hide().attr("disabled", true).addClass("hide");
} else {
$('#stateprovince_select select').html('').hide().attr("disabled", true).addClass("hide");
$('#stateprovince_text input[type="text"]').show().attr("disabled", true).removeClass("hide");
$('#StateProvinceCode').hide();
}
});
});
});
</script>
jQuery在Controller中调用此例程:
[AllowAnonymous]
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult StateList(int countryid)
{
var state = from s in dbLocations.States
where s.CountryId == countryid
select s;
return Json(new SelectList(state.ToArray(), "StateId", "StateName"), JsonRequestBehavior.AllowGet);
}
可能比您需要的更多。我做了一些更改以反映ModelView的更改,但我还没有能够运行应用程序 - 仍在进行更改。我知道,jQuery需要一些清理工作。 ;)
答案 0 :(得分:1)
您应该在Id列上保留Key
索引,但为CountryCode
添加唯一约束。这有以下好处:
您的关系都使用整数Id列,其效果优于连接字符串。
CountryCode现在不允许重复输入。
可以向用户显示CountryCode,并隐藏数据库与整数链接的事实。
所以现在你的模型看起来像这样:
public class Country
{
[Key]
public int Id { get; set; }
[Index("UX_Country_CountryCode", IsUnique = true)]
[MaxLength(10)]
public string CountryCode { get; set; }
public string CountryName { get; set; }
public virtual ICollection<State> States { get; set; }
}
public class State
{
[Key]
public int Id { get; set; }
[Index("UX_State_StateCode", IsUnique = true)]
[MaxLength(10)]
public string StateCode { get; set; }
public string StateName { get; set; }
[ForeignKey("Country")]
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}
如果您希望能够在不同的国家/地区拥有相同的州代码,请扩展这样的唯一约束:
public class State
{
[Key]
public int Id { get; set; }
[Index("UX_State_StateCodeCountryId", IsUnique = true, Order = 1)]
[MaxLength(10)]
public string StateCode { get; set; }
public string StateName { get; set; }
[ForeignKey("Country")]
[Index("UX_State_StateCodeCountryId", IsUnique = true, Order = 0)]
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}