如何首先使用EF模型/数据查询WCF服务

时间:2012-03-28 14:41:55

标签: wcf entity-framework entity-framework-4

我有一个客户端项目和一个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";
        }
    }
}

}

2 个答案:

答案 0 :(得分:0)

当您使用EF时,它不会假设对数据库有任何直接查询。花了一些时间阅读什么是领域驱动设计。描述了策略Persistent Ignorance,这意味着,在设计系统时,根本不应考虑数据存储。仅适用于模型。 Data Mapper模式描述了应该完成与数据库相关的所有事情的位置。 Here是一篇很好的文章,我认为可以帮助你 另一个建议,不要忘记MVC支持宁静的Web开发风格。利用这些功能应该有助于您的设计。

答案 1 :(得分:0)

paramosh,

那么你能否向新手解释呢?我只是去了那个网站,并仔细阅读了那个页面,但是尝试精简EF网络并没有多大帮助(这主要是为了强化我在EF之前做的事情)。