Reputation: 3109
Greetings!
I'm using SPROCs within Entity Framework for all of my CRUD methods. Because this is a multi-tenant database, we have a clientID field in each of the tables. Our DBA doesn't want that clientID exposed, so we pass a username into the SPROC (username of authenticated user, tracked in the membership provider), which then handles conversion of username to clientID internally within sproc.
The issue I'm having is that my Entities don't have the Username property. When I create my function imports for insert/update/delete, the mapping is requesting a Username field (required, from my SPROC) which doesn't exist in my entity. Here's my schema:
Account Entity
AccountNumber
AccountDescription
ClientID
ActiveFlag
RowVersion (for concurrency)
And my SPROC:
ALTER PROCEDURE [dbo].[GetAccounts]
@Username varchar (60)
AS
/*********************************************
Summary: Get Accounts
2011-01-20 aca initial version
2011-01-27 aca Alias for Description
2011-03-21 aca Implement user security
********************************************/
select P.FERC_ACCOUNT,
P.[DESCRIPTION] as AccountDescription,
P.RowVersion
from dbo.P_ACCOUNTS P
join dbo.v_UserClient U
on U.Username = @Username
and P.CLIENT_ID = U.Client_ID
where P.ActiveFlag = 1;
RETURN 0;
I'm not sure what the best way to proceed is. Do I just create a Username property in my entity? That means I'd have to do this on every one? How do I populate it? Etc etc :)
Thanks for your help!
Scott
Upvotes: 2
Views: 447
Reputation: 9478
I have the same restrictions and I export the stored procedures as functions. For procedures that do not have output parameters I return the default generated complex type i.e. GetAccountsResult.
public IEnumerable<GetAccountsResult> GetAccounts(string username)
{
return ObjectContext.GetAccounts(username).AsQueryable();
}
The complex type needs to have a property designated as the [Key]. To set the key for complextypes I create a partial for my domain service and use a buddy class to set the key. So for AccountsDomainService.cs I create AccountsDomainService.metadata.cs.
[MetadataType(typeof(GetAccountsResultMetadata))]
public partial class GetAccountsResult
{
internal sealed class GetAccountsResultMetadata
{
[Key]
public int Id { get; set; }
}
}
For procedures that do have output parameters I create a poco object containing properties for the output parameters and another poco object matching the complex type. I then use AutoMapper to map the returned complex type to my created complex type. I do this so I can return the relation.
Account.cs
public class Account
{
[Key]
public int Id { get; set; }
public string MyOutputParameter { get; set; }
[Include, Association("Account_AccountDetails", "Id", "AccountId")]
public List<AccountDetail> AccountDetails { get; set; }
}
AccountDetail.cs
public class AccountDetail
{
[Key]
public int Id { get; set; }
public int AccountId { get; set; }
public string MyAccountDetailProperty { get; set; }
}
AccountDomainService.cs
public Account GetAccountsWithOutputParms(string username)
{
var myOutputParameter = new ObjectParameter("MyOutPutParameter", typeof(int));
var tempGetAccountsResult = ObjectContext.GetAccounts(username).ToList();
var account = new Account
{
Id = 1,
MyOutputParameter = myOutputParameter,
AccountDetails = Mapper.Map<List<GetAccountsResult>, List<AccountDetail>>(tempGetAccountsResult)
};
return accout;
}
When I get those results on the client, I use AutoMapper to map them to client side view models.
This article Stored Procedures with EF 4 and RIA Services is handy.
For insert/update you can create a poco object that models the procedure parameters and pass it to your exported function in your domain service.
Upvotes: 1