【发布时间】:2012-03-28 14:41:54
【问题描述】:
我有一个客户端项目和一个向客户端公开 WCF 服务的 MVC3 EF 模型优先项目。我是 EF 新手,有些事情不是很清楚。
假设 Northwind 服务带有 Product 实体,如果我想做一个简单的查询,比如返回具有特定价格的产品,我在哪里编写查询代码?
在服务器端只有 EDM 和服务本身,它非常简单,几乎没有任何代码。
在客户端我有 Product 模型类和 NorthwindContext 以及 ProdcutsPageViewModel 类(这是一个 MVVM 项目)
所以我的问题是,我如何以及在哪里对数据库进行查询?我是否通过将 LINQ 代码附加到 URI 从客户端实现它?我是否通过向服务添加新方法从服务器端实现它?如果您能向新手解释一下,我将不胜感激,
谢谢!
这里是一些代码:
在服务器上,NorthwindODataService 服务类:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class NorthwindODataService : DataService<NorthwindEntities>
{
private readonly IUserPrivilegesRepository userPrivilegesRepository;
private readonly IClaimsIdentity identity;
public NorthwindODataService()
: this(HttpContext.Current.User.Identity as IClaimsIdentity, new InfrastructureEntities())
{
}
public NorthwindODataService(IClaimsIdentity identity, IUserPrivilegesRepository userPrivilegesRepository)
{
this.identity = identity;
this.userPrivilegesRepository = userPrivilegesRepository;
}
protected string UserId
{
get
{
var nameIdentifierClaim = this.identity.Claims.SingleOrDefault(c => c.ClaimType == ClaimTypes.NameIdentifier);
if (nameIdentifierClaim == null)
{
throw new DataServiceException(401, "Unauthorized", "The request requires authentication.", "en-US", null);
}
return nameIdentifierClaim.Value;
}
}
/// <summary>
/// Initializes service-wide policies. This method is called only once.
/// </summary>
/// <param name="config"></param>
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Products", EntitySetRights.All);
config.SetEntitySetAccessRule("Categories", EntitySetRights.AllRead);
config.SetEntitySetAccessRule("Suppliers", EntitySetRights.AllRead);
config.SetEntitySetPageSize("Products", 20);
config.SetEntitySetPageSize("Categories", 20);
config.SetEntitySetPageSize("Suppliers", 20);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
}
/// <summary>
/// Define a query interceptor for the Products entity set.
/// </summary>
/// <returns></returns>
[QueryInterceptor("Products")]
public Expression<Func<Product, bool>> OnQueryProducts()
{
this.ValidateAuthorization("Products", PrivilegeConstants.SqlReadPrivilege);
// The user has Read permission.
return p => true;
}
/// <summary>
/// Define a query interceptor for the Categories entity set.
/// </summary>
/// <returns></returns>
[QueryInterceptor("Categories")]
public Expression<Func<Category, bool>> OnQueryCategories()
{
this.ValidateAuthorization("Categories", PrivilegeConstants.SqlReadPrivilege);
// The user has Read permission.
return p => true;
}
/// <summary>
/// Define a query interceptor for the Suppliers entity set.
/// </summary>
/// <returns></returns>
[QueryInterceptor("Suppliers")]
public Expression<Func<Supplier, bool>> OnQuerySuppliers()
{
this.ValidateAuthorization("Suppliers", PrivilegeConstants.SqlReadPrivilege);
// The user has Read permission.
return p => true;
}
/// <summary>
/// Define a change interceptor for the Products entity set.
/// </summary>
/// <param name="product"></param>
/// <param name="operations"></param>
[ChangeInterceptor("Products")]
public void OnChangeProducts(Product product, UpdateOperations operations)
{
if (operations == UpdateOperations.Change)
{
this.ValidateAuthorization("Products", PrivilegeConstants.SqlUpdatePrivilege);
var entry = default(ObjectStateEntry);
if (this.CurrentDataSource.ObjectStateManager.TryGetObjectStateEntry(product, out entry))
{
// Reject changes to a discontinued Product.
// Because the update is already made to the entity by the time the
// change interceptor in invoked, check the original value of the Discontinued
// property in the state entry and reject the change if 'true'.
if ((bool)entry.OriginalValues["Discontinued"])
{
throw new DataServiceException(400, "Bad Request", "A discontinued product cannot be modified.", "en-US", null);
}
}
else
{
throw new DataServiceException(404, "Not Found", "The requested product could not be found in the data source.", "en-US", null);
}
}
else if (operations == UpdateOperations.Add)
{
this.ValidateAuthorization("Products", PrivilegeConstants.SqlCreatePrivilege);
}
else if (operations == UpdateOperations.Delete)
{
this.ValidateAuthorization("Products", PrivilegeConstants.SqlDeletePrivilege);
var entry = default(ObjectStateEntry);
if (this.CurrentDataSource.ObjectStateManager.TryGetObjectStateEntry(product, out entry))
{
// Only a discontinued Product can be deleted.
if (!(bool)entry.OriginalValues["Discontinued"])
{
throw new DataServiceException(400, "Bad Request", "Products that are not discontinued cannot be deleted.", "en-US", null);
}
}
else
{
throw new DataServiceException(404, "Not Found", "The requested product could not be found in the data source.", "en-US", null);
}
}
}
private static string BuildMessage(string entitySetName, string privilege)
{
var message = string.Empty;
switch (privilege)
{
case PrivilegeConstants.SqlCreatePrivilege:
message = string.Format(CultureInfo.InvariantCulture, "You are not authorized to create new rows in the {0} entity set.", entitySetName);
break;
case PrivilegeConstants.SqlReadPrivilege:
message = string.Format(CultureInfo.InvariantCulture, "You are not authorized to query the {0} entity set.", entitySetName);
break;
case PrivilegeConstants.SqlUpdatePrivilege:
message = string.Format(CultureInfo.InvariantCulture, "You are not authorized to update rows in the {0} entity set.", entitySetName);
break;
case PrivilegeConstants.SqlDeletePrivilege:
message = string.Format(CultureInfo.InvariantCulture, "You are not authorized to delete rows in the {0} entity set.", entitySetName);
break;
default:
message = string.Format(CultureInfo.InvariantCulture, "You are not authorized to access the {0} entity set.", entitySetName);
break;
}
return message;
}
private void ValidateAuthorization(string entitySetName, string privilege)
{
if (!this.userPrivilegesRepository.HasUserPrivilege(this.UserId, privilege))
{
// The user does not have Read permission.
throw new DataServiceException(401, "Unauthorized", BuildMessage(entitySetName, privilege), "en-US", null);
}
}
}
}
在客户端,Product 模型类:
[EntitySetAttribute("Products")]
[DataServiceKeyAttribute("ProductID")]
public class Product : INotifyPropertyChanged
{
private int id;
private string productName;
private int? supplierID;
private int? categoryID;
private string quantityPerUnit;
private decimal? unitPrice;
private short? unitsInStock;
private short? unitsOnOrder;
private short? reorderLevel;
private bool discontinued;
public event PropertyChangedEventHandler PropertyChanged;
public int ProductID
{
get
{
return this.id;
}
set
{
this.id = value;
this.OnPropertyChanged("ProductID");
}
}
public string ProductName
{
get
{
return this.productName;
}
set
{
this.productName = value;
this.OnPropertyChanged("ProductName");
}
}
public int? SupplierID
{
get
{
return this.supplierID;
}
set
{
this.supplierID = value;
this.OnPropertyChanged("SupplierID");
}
}
public int? CategoryID
{
get
{
return this.categoryID;
}
set
{
this.categoryID = value;
this.OnPropertyChanged("CategoryID");
}
}
public string QuantityPerUnit
{
get
{
return this.quantityPerUnit;
}
set
{
this.quantityPerUnit = value;
this.OnPropertyChanged("QuantityPerUnit");
}
}
public decimal? UnitPrice
{
get
{
return this.unitPrice;
}
set
{
this.unitPrice = value;
this.OnPropertyChanged("UnitPrice");
}
}
public short? UnitsInStock
{
get
{
return this.unitsInStock;
}
set
{
this.unitsInStock = value;
this.OnPropertyChanged("UnitsInStock");
}
}
public short? UnitsOnOrder
{
get
{
return this.unitsOnOrder;
}
set
{
this.unitsOnOrder = value;
this.OnPropertyChanged("UnitsOnOrder");
}
}
public short? ReorderLevel
{
get
{
return this.reorderLevel;
}
set
{
this.reorderLevel = value;
this.OnPropertyChanged("ReorderLevel");
}
}
public bool Discontinued
{
get
{
return this.discontinued;
}
set
{
this.discontinued = value;
this.OnPropertyChanged("Discontinued");
}
}
public static Product CreateProduct(int productID, string productName, bool discontinued)
{
return new Product
{
ProductID = productID,
ProductName = productName,
Discontinued = discontinued,
};
}
protected virtual void OnPropertyChanged(string changedProperty)
{
var propertyChanged = this.PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(changedProperty));
}
}
}
}
还有NorthwindContext 类:
public class NorthwindContext : DataServiceContext
{
public NorthwindContext(Uri serviceRoot)
: base(serviceRoot)
{
this.MergeOption = MergeOption.OverwriteChanges;
this.SaveChangesDefaultOptions = SaveChangesOptions.ContinueOnError;
}
public void AddToCategories(Category category)
{
this.AddObject("Categories", category);
}
public void AddToProducts(Product product)
{
this.AddObject("Products", product);
}
public void AddToSuppliers(Supplier supplier)
{
this.AddObject("Suppliers", supplier);
}
public void AttachToCategories(Category category)
{
this.AttachTo("Categories", category);
}
public void AttachToProducts(Product product)
{
this.AttachTo("Products", product);
}
public void AttachToSuppliers(Supplier supplier)
{
this.AttachTo("Suppliers", supplier);
}
}
}
这里是ProductsPageViewModel 类:
public class ProductsPageViewModel : ListViewModel<Product>
{
public ProductsPageViewModel()
: this(Deployment.Current.Dispatcher, App.CloudClientFactory.ResolveNorthwindContext())
{
}
public ProductsPageViewModel(Dispatcher dispatcher, NorthwindContext northwindContext)
: base(dispatcher, northwindContext)
{
}
protected override string EntitySetName
{
get
{
return "Products";
}
}
}
}
【问题讨论】:
标签: wcf entity-framework entity-framework-4