问题
If I have an ObjectDataSource setup like:
<asp:ObjectDataSource
ID="ObjectDataSource1"
runat="server"
DataObjectTypeName="Employee"
InsertMethod="Insert"
UpdateMethod="Update"
DeleteMethod="Select"
TypeName="EmployeeDB">
</asp:ObjectDataSource>
and a data/business object with methods like:
public class EmployeeDB
{
public void Insert(Employee emp)
public int Update(Employee emp)
public bool Delete(int id)
}
How do I get the objectdatasource to use the Delete method with the parameter that is not an Employee object?
If this is not possible, what is the recommended alternative architecture?
Edit:
To clarify, I want to use the method signature on my data/business object as shown above, however if I try to allow an Employee object to be passed into some of the methods using DataObjectTypeName, then I seemingly lose the ability to have some methods take just an integer id for instance.
If I do not use the DataObjectTypeName, then I have to place all the method parameters in the ObjectDataSource and change the methods on the data/business object to match, this seems like a bad design choice because as the Employee object changes I will have to update each of these methods. Is there a better architecture?
回答1:
Here is solution and it is working for me for update operation then delete far easier than update :
Create Class to pass parameter. For Example : I am passing paramter for Usermaster table : UserMasterDT :
public UserMasterDT(int userid, int roleid, string Firstname, string ) { this.muserid = userid; this.mroleid = roleid; this.mfirstname = Firstname; this.mlastname = Lastname; } //Here set this prop as DUMMY output variable, that u used everywhere to get output value public int iRecUpdated { get { return mrecupdated; } set { mrecupdated = value; } }
I am binding objectdatasource to formview for update uperation.Set objectdatasource as follows :
<asp:ObjectDataSource ID="odsUser" runat="server" TypeName="MMCTaxINTLXMLValidation.UserBLL" SelectMethod="GetUserRoleByUserId" DataObjectTypeName="MMCTaxINTLXMLValidation.UserMasterDT" OldValuesParameterFormatString="original_{0}" UpdateMethod="UpdateUserWithTransaction" onupdated="odsUser_Updated"> <SelectParameters> <asp:QueryStringParameter Name="iUId" QueryStringField="UserId" Type="Int32" DefaultValue="-1" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="UserId" Type="Int32" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="RoleId" Type="Int32" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Firstname" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Lastname" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="BirthDate" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="MMCEmail" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Homecontact" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Officecontact" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Cellcontact" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Logon" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="Password" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="PasswordQ1" Type="String" ConvertEmptyStringToNull="true" /> <asp:Parameter Name="PasswordA1" Type="String" ConvertEmptyStringToNull="true" /> </UpdateParameters> </asp:ObjectDataSource>
NOTICE THERE IS NO ANY OUTPUT PARAMTER HERE
Now, IN U R BLL In update method, pass and return UserMasterDT as input and output. DO NOT PASS SEPERATE PARAMETER AND OUT VARAIBLE . Write code like :
HERE I AM PASSING UserMasterDT AS IN AND OUT
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)] public UserMasterDT UpdateUserWithTransaction(UserMasterDT tempuser) { int iRecUpdated = -1; Adapter.BeginTransaction(); try { string sFlag = "UpdateUserRole"; int iUserId = tempuser.UserId; int iRoleId = tempuser.RoleId; string sFirstname = tempuser.Firstname; string sLastname = tempuser.Lastname; int? iReturnData; //THIS OUT IS FROM MY SQL STORED PROCE NOT WITH OBJECTDATASOURCE OUT PARAMETER. IT HAS NOTHING TO DO WITH OBJECT DATA SOUCE. Adapter.UpdateUserRole(sFlag,iUserId,iRoleId,sFirstname,sLastname,out iReturnData); if (iReturnData == 1) { iRecUpdated = 1; this.Adapter.CommitTransaction(); } else if (iReturnData == null) iRecUpdated = -1; //What ever is return, set it back to UserMasterDT's iRecUpdated prop tempuser.iRecUpdated = iRecUpdated; return tempuser; } catch (Exception ex) { if (ex != null) { Adapter.RollbackTransaction(); //CustomEX objCUEx = new CustomEX(ex.Message, ex); ex = null; iRecUpdated = -1; //-1 : Unexpected Error //What ever is return, set it back to UserMasterDT's iRecUpdated prop tempuser.iRecUpdated = iRecUpdated; return tempuser; } } finally { tempuser.iRecUpdated = iRecUpdated; } //Return tempuser back return tempuser; }
then in aspx.cs page read property of UserMasterDT as follows :
if (e.Exception == null) { UserMasterDT tempuser = (UserMasterDT) e.ReturnValue; lblMsg.Text = "Record Updated : " + tempuser.iRecUpdated.ToString(); }
My stored proc is :
set ANSI_NULLS ON create PROCEDURE [dbo].[UpdateUserRole] ( @sFlag varchar(50), @iUserId int, @iRoleId int, @sFirstname varchar(50), @sLastname varchar(50), @iReturnData int output ) as Begin Declare @errnum as int Declare @errseverity as int Declare @errstate as int Declare @errline as int Declare @errproc as nvarchar(100) Declare @errmsg as nvarchar(4000) ----------------------- if @sFlag = upper('UPDATEUSERROLE') begin begin try begin tran --Update User Master Table UPDATE tblUserMaster SET Firstname = @sFirstname, Lastname = @sLastname, WHERE UserId = @iUserId --Update tblUserRolesTran Table update tblUserRolesTran set roleid = @iRoleId where Userid = @iUserId commit tran -- If commit tran execute then trancount will decrease by 1 -- Return Flag 1 for update user record and role record SET @iReturnData = 1 end try begin catch IF @@Trancount > 0 -- Get Error Detail In Variable Select @errnum =@@ERROR, @errseverity = ERROR_SEVERITY(), @errstate = ERROR_STATE(), @errline = ERROR_LINE(), @errproc = ERROR_PROCEDURE(), @errmsg = ERROR_MESSAGE() rollback tran -- To see print msg, keep raise error on, else these msg will not be printed and dislayed print '@errnum : ' + ltrim(str(@errnum )) print '@errseverity : ' + ltrim(str(@errseverity)) print '@errstate : ' + ltrim(str(@errstate)) print '@errline : ' + ltrim(str(@errline)) print '@errproc : ' + @errproc print '@errmsg : ' + @errmsg --Raise error doesn't display error message below 50000 --So we have to create custom message and add to error table using sp_addmessage ( so_addmessage is built-in sp) --In custom error message we have line number and error message Declare @custerrmsg as nvarchar(4000) Select @custerrmsg = 'Proc: UpdateUserRole, Line: ' + ltrim(str(@errline)) + ': ' + @errmsg if (@errnum < 50000) EXEC SP_ADDMESSAGE @msgnum = 50002, @severity = 16, @msgtext = @custerrmsg, @replace = 'REPLACE' --After adding custom error message we need to raise error --Raise error will appear at client (.net application) RAISERROR(50002,16,1) end catch end set nocount off End
Hope this helps you whatever u need to do. sairam
回答2:
When you bind your objectdatasource to a control, you should be able to get an Id (in your example, I would assume EmployeeId) based on the data you try to bind to, and then you can set this as a delete parameter.
check out msdn example here.
<asp:objectdatasource
id="ObjectDataSource1"
runat="server"
selectmethod="GetAllEmployees"
deletemethod="DeleteEmployee"
ondeleting="NorthwindEmployeeDeleting"
ondeleted="NorthwindEmployeeDeleted"
typename="Samples.AspNet.CS.EmployeeLogic">
<deleteparameters>
<asp:parameter name="EmpID" type="Int32" />
</deleteparameters>
</asp:objectdatasource>
回答3:
You have to remove DataObjectTypeName="Employee"
from your object data source declaration. This property gets and sets the name of the class that the ObjectDataSource control uses for a parameter in your delete method.
<asp:ObjectDataSource
ID="ObjectDataSource1"
runat="server"
InsertMethod="Insert"
UpdateMethod="Update"
DeleteMethod="Delete"
TypeName="EmployeeDB">
<deleteparameters>
<asp:parameter name="EmpID" type="Int32" />
</deleteparameters>
</asp:ObjectDataSource>
回答4:
Even if you implement your class as follows:
public class EmployeeDB
{
public Employee Insert(Employee emp)
public Employee Update(Employee emp)
public void Delete(Employee emp)
}
You will only get the fields bound to the 'DataKeys' passed through on the object when you try to delete, eg the ID.
*On a side note, returning the object after an Insert or Update allows the DataView to update the row.
The way I remember it working was you can configure your ObjectDataSource to pass through parameters to your db layer OR pass though the objects, NOT a combination of both.
Which means the following would be possible with the manually configured parameters:
public class EmployeeDB
{
public int Insert(string name, DateTime dob)
public int Update(int id, string name, DateTime dob)
public void Delete(int id)
}
回答5:
I was using LinqToSql for a project similar to this a short while ago. I had two different types of delete methods:
public void DeleteDisconnected(Product original_entity)
{
var db = new RmsConcept2DataContext(base.ConnectionString);
db.Products.Attach(original_entity, false);
db.Products.DeleteOnSubmit(original_entity);
db.SubmitChanges();
}
public void Delete(int ID)
{
var db = new RmsConcept2DataContext(base.ConnectionString);
Product product = db.Products.Single(p => p.ProductID == ID);
// delete children
foreach (Release release in product.Releases)
db.Releases.DeleteOnSubmit(release);
db.Products.DeleteOnSubmit(product);
db.SubmitChanges();
}
.. you can see the DeleteDisconnected
method is designed to accept the whole entity object from the 'ObjectDataSource'. I was using the
ConflictDetection="CompareAllValues"
..and
OldValuesParameterFormatString="original_{0}"
..params on the 'ObjectDataSource' for this case but you may not need to do that. I think i could still get concurrency exceptions on deletes with the above approach - which is what i wanted at the time - to make use of LinqToSql's built in conflict detection/concurrency features.
Your architecture depends on how you handle data, etc in lower layers of your app (which you don't seem mention much about in the question). It is definitely more mature design to pass around the business objects rather than all the fields as method params. But occasionly (for delete functions) only the int
ID is necessary.. but it depends on your underlying implementation.
回答6:
The objects method signature variable names must match the objects property names exactly and it will work. eg edit* also dont forget the DataKeyNames attribute
public class EmployeeDB
{
public int ID{get;set;}
public string Name {get;set;}
public ing Age{get;set;}
//both these would work
public void Insert(Employee emp)
public void Insert(string Name,int Age)
//both these would work
public void Update(Employee emp)
public void Update(int ID,string Name,int Age)
//works
public void Delete(Employee emp)
//WONT work
public bool Delete(int empId)
//will work
public void Delete(int ID)
}
<asp:ObjectDataSource
ID="ObjectDataSource1"
runat="server"
DataObjectTypeName="Employee"
InsertMethod="Insert"
UpdateMethod="Update"
DeleteMethod="Select"
TypeName="EmployeeDB"
DataKeyNames="ID">
<DeleteParameters>
<asp:Parameter Name="ID" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
回答7:
Got to this question hoping to solve this exact dilemma, and after trying what other answers propose, got to the conclusion that you just CAN'T mix methods. Either all your methods (Insert, Update, Delete) have:
- a single custom class parameter (whose type is specified at the
DataObjectTypeName
attribute), or - a list of parameters for each of the properties (specified within each
<InsertParameters>
,<UpdateParameters>
or<DeleteParameters>
).
You can't have Insert
method using the single parameter version and the Delete
method using just an Int32
parameter. My findings got confirmed when I read the ObjectDataSource documentation which clearly says:
When the DataObjectTypeName property is set and the ObjectDataSource control is associated with a data-bound control, the methods that are specified by the InsertMethod and DeleteMethod properties must each have one parameter of the type that is specified in the DataObjectTypeName property.
The only exception might be the Update
method which can have one or two parameters depending upon the ConflictDetection
property, but that's a whole different story.
The only solution I got to was to overload the Delete
method to trick the ObjectDataSource
, and internally call my Delete
method with the Int32
parameter:
// This method gets called by the ObjectDataSource
public Int32 Delete(MyCustomClass foo)
{
// But internally I call the overloaded method
Delete(foo.Id);
}
public Int32 Delete(Int32 id)
{
// Delete the item
}
回答8:
In case when DataObjectTypeName is used instead of separate parameters, the business object you are using will work. You just need to add DataKeyNames="Id" where Id is the primary key field in Your Bound control like GridView or something else.
It will populate your type parameter, in your case "Employee" type with "Id" value which can be used to delete entity.
来源:https://stackoverflow.com/questions/913571/using-objectdatasource-and-dataobjecttypename-how-do-you-handle-delete-methods