我有一个客户端项目和一个MVC3 EF模型第一个项目,它向客户端公开WCF服务。我是EF的新手,有些事情不太清楚。
让我们假设使用Product实体的Northwind服务,如果我想做一个简单的查询,比如返回具有特定价格的产品,我在哪里编写查询代码?
在服务器端只有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";
}
}
}
}
答案 0 :(得分:0)
当您使用EF时,它不会假设对数据库有任何直接查询。花了一些时间阅读什么是领域驱动设计。描述了策略Persistent Ignorance,这意味着,在设计系统时,根本不应考虑数据存储。仅适用于模型。 Data Mapper模式描述了应该完成与数据库相关的所有事情的位置。 Here是一篇很好的文章,我认为可以帮助你 另一个建议,不要忘记MVC支持宁静的Web开发风格。利用这些功能应该有助于您的设计。
答案 1 :(得分:0)
paramosh,
那么你能否向新手解释呢?我只是去了那个网站,并仔细阅读了那个页面,但是尝试精简EF网络并没有多大帮助(这主要是为了强化我在EF之前做的事情)。