【问题标题】:How to make queries to a WCF service with EF model / data first如何首先使用 EF 模型/数据对 WCF 服务进行查询
【发布时间】: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


    【解决方案1】:

    当您使用 EF 时,它不会假设对数据库有任何直接查询。花一些时间阅读什么是领域驱动设计。描述了持久无知策略,这意味着,当您设计系统时,您根本不应该考虑数据存储。仅使用模型。数据映射器模式描述了与数据库相关的所有事情都应该完成的地方。 Here 是好文章,我觉得可以帮到你。
    另一个建议,不要忘记 MVC 支持 RESTful 风格的 Web 开发。利用这些功能应该有助于您的设计。

    【讨论】:

      【解决方案2】:

      帕拉莫什,

      所以你能不能向新手解释一下?我刚刚去了那个网站,并通读了那个页面,但这对于尝试精简 EF 网络并没有太大帮助(它主要是加强我在 EF 之前的工作方式)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多