我遇到了使用SELECT来处理Angular,ASP.NET Web API v2和Entity Framework Code First的问题。我有两个简单的对象,产品和类别,使用以下模型定义:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string SerialNumber { get; set; }
public string Notes { get; set; }
public Category Category { get; set; }
public ApplicationUser User { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ApplicationUser User { get; set; }
}
然后我有以下Angular Markup:
<div class="form-group">
<label for="inputSerial" class="col-lg-3 control-label">Category</label>
<div class="col-lg-9">
<select class="form-control" id="selectCategory" ng-model="product.Category" ng-options="category as category.Name for category in categories"></select>
</div>
</div>
最后,以下Angular app.js脚本:
app.controller('SerialController', function ($scope, $http, $routeParams, $cookies) {
$http({
method: 'GET',
url: 'http://localhost:20697/api/categories/' + '?access_token=' + $cookies.token,
headers: { 'Authorization': 'Bearer ' + $cookies.token }
}).success(function (data, status, headers) {
$scope.categories = data;
}).error(function (data, status, headers) {
$scope.error = reason;
});
var onGetComplete = function (response) {
$scope.product = response.data;
};
var onError = function (reason) {
$scope.error = reason;
};
if ($routeParams.id > 0) {
$http.get("http://localhost:20697/api/products/" + $routeParams.id)
.then(onGetComplete, onError);
}
$scope.saveProduct = function () {
if ($scope.product.Id > 0) {
$http({
method: 'PUT',
data: $scope.product,
url: 'http://localhost:20697/api/products/' + $scope.product.Id
}).success(function (data, status, headers) {
}).error(function (data, status, headers) {
});
}
else {
$http({
method: 'POST',
data: $scope.product,
url: 'http://localhost:20697/api/products/'
}).success(function (data, status, headers) {
}).error(function (data, status, headers) {
});
}
};
});
有了这个,我正在使用数据库中的类别正确填充SELECT。但是,我有两个问题。
问题#1)如果在数据库中设置了类别,则会将其从Web api发送到Angular,但实际上并未在select中选择正确的条目。
问题#2)当我在下拉列表中选择一个条目并保存时,angular正在将产品对象发送回具有正确类别集的api。我甚至可以在api控制器中看到它。但实际上并没有将类别选择保存到数据库中的产品中。这是我的产品更新控制器代码:
// PUT: api/Products/5
[ResponseType(typeof(void))]
public IHttpActionResult PutProduct(int id, Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != product.Id)
{
return BadRequest();
}
db.Entry(product).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
在实际数据库中,Entity Framework Code首先将products表中的类别添加为Category_Id,这是我所期望的。
对此有任何帮助将不胜感激。谢谢!
更新:在以下建议不能正常工作之后,我在网上进行了更多搜索。我从Scott Allen那里找到了这篇文章。 http://odetocode.com/blogs/scott/archive/2013/06/19/using-ngoptions-in-angularjs.aspx。从那以后,我能够使用我的原始代码,但随后在角度控制器中添加一些代码来进行初始选择。我还必须改变控制器中的事物顺序(一旦我开始工作,我需要进一步重构它)。这是控制器的更新部分:
$http({
method: 'GET',
url: 'http://localhost:20697/api/categories/' + '?access_token=' + $cookies.token,
headers: { 'Authorization': 'Bearer ' + $cookies.token }
}).success(function (data, status, headers) {
$scope.categories = data;
if ($routeParams.id > 0) {
$http.get("http://localhost:20697/api/products/" + $routeParams.id)
.then(onGetComplete, onError);
}
}).error(function (data, status, headers) {
$scope.error = reason;
});
var onGetComplete = function (response) {
$scope.product = response.data;
for (var i = 0; i < $scope.categories.length; i++) {
if ($scope.categories[i].Id == $scope.product.Category.Id) {
$scope.product.Category = $scope.categories[i];
break;
}
}
};
有了这个,我现在能够使初始选择工作,并且正确的类别选择将被发送回API。 问题是,无论出于何种原因,实体框架在更新产品时都会跳过类别选择。以下是正在执行的T-SQL:
DECLARE @2 AS SQL_VARIANT;
DECLARE @0 AS SQL_VARIANT;
DECLARE @1 AS SQL_VARIANT;
SET @2 = NULL;
SET @0 = NULL;
SET @1 = NULL;
UPDATE [dbo].[Products]
SET [Name] = @0, [SerialNumber] = @1, [Notes] = NULL
WHERE ([Id] = @2)
如您所见,Category_Id根本没有得到更新。有什么我必须要告诉EF它应该更新类别的外键以及产品信息吗?
由于
答案 0 :(得分:0)
这是你的问题的角度部分的想法。我们在选择框中尝试使用对象时遇到了问题。在Angular中,ngModel按引用进行比较,而不是值。绑定到对象数组时这很重要。我猜你的项目没有被选中,因为你的参考文献是不同的。我们现在写这样的ng-option表达式:
<select ng-model="product.category.id" ng-option="category.id as category.Name for category in categories" />
而不是匹配整个对象,这将允许您只匹配id或我们认为有点清洁的其他属性。希望这有帮助!
更新
试试这个,看看它是否适合你:
查看更新:
<select ng-model="categoryId" ng-option="category.id as category.Name for category in categories" />
控制器更新:
app.controller('SerialController', function ($scope, $http, $routeParams, $cookies) {
$scope.categoryId = 0;
$http({
method: 'GET',
url: 'http://localhost:20697/api/categories/' + '?access_token=' + $cookies.token,
headers: { 'Authorization': 'Bearer ' + $cookies.token }
}).success(function (data, status, headers) {
$scope.categories = data;
}).error(function (data, status, headers) {
$scope.error = reason;
});
var onGetComplete = function (response) {
$scope.product = response.data;
$scope.categoryId = $scope.product.category.Id;
};
var onError = function (reason) {
$scope.error = reason;
};
if ($routeParams.id > 0) {
$http.get("http://localhost:20697/api/products/" + $routeParams.id)
.then(onGetComplete, onError);
}
$scope.saveProduct = function () {
$scope.product.category.Id = $scope.categoryId;
if ($scope.product.Id > 0) {
$http({
method: 'PUT',
data: $scope.product,
url: 'http://localhost:20697/api/products/' + $scope.product.Id
}).success(function (data, status, headers) {
}).error(function (data, status, headers) {
});
}
else {
$http({
method: 'POST',
data: $scope.product,
url: 'http://localhost:20697/api/products/'
}).success(function (data, status, headers) {
}).error(function (data, status, headers) {
});
}
};
});
答案 1 :(得分:0)
所以在继续挖掘并尝试之后。看起来这是由于我只有一个导航属性而没有外键返回到类别表。我真的不喜欢这个解决方案,但它确实有效。我认为有两件事情很糟糕,如果有人能给我一些关于更好修复方法的想法,我会很高兴。
第一步修复:我必须更新我的Product类以包含对类别的外键引用:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string SerialNumber { get; set; }
public string Notes { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
public ApplicationUser User { get; set; }
}
然后在让Entity Framework更新我的数据库之后遇到各种痛苦的挣扎之后,我创建了一个全新的数据库并且它有效。而不是数据库现在在products表中具有列Category_Id,它现在具有预期的CategoryId。我第一次想到的就是这个。我真的不希望没有这个额外的财产来处理。
第二步修复:这是添加其他类别的副产品。我相信我可以通过更改我的ng-model和ng-options来使用CategoryId而不是对象来修复它。但是为了时间的推移,我继续在更新中将以下代码添加到ProductsController:
if (product.Category.Id != product.CategoryId)
{
product.CategoryId = product.Category.Id;
}
理想情况下..如果我可以按原样离开我的模型,并且只有导航属性,那将是最好的。也许我会通过注释添加外键。如果有人想知道如何改善这一点,请告诉我。
谢谢!