У меня есть клиентский проект и первый проект модели MVC3 EF, который предоставляет клиенту сервис WCF. Я новичок в 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";
}
}
}
}