Silverlight DataContext: Changes also being made in Cloned Object - c#

Consider follwing method of copying/cloning an object (all fields are copied into a new object)
public AangepastWerk CloneAdjustedWork(AangepastWerk pAdjustedWork)
{
return new AangepastWerk()
{
AangepastWerkID = pAdjustedWork.AangepastWerkID,
ArbeidsOngeval = pAdjustedWork.ArbeidsOngeval,
DatumCreatie = pAdjustedWork.DatumCreatie,
DatumLaatsteWijziging = pAdjustedWork.DatumLaatsteWijziging,
DatumOngeval = pAdjustedWork.DatumOngeval,
GewijzigdDoor = pAdjustedWork.GewijzigdDoor,
NietErkend = pAdjustedWork.NietErkend,
Stamnummer = pAdjustedWork.Stamnummer,
Verzorging = pAdjustedWork.Verzorging,
VerzorgingId = pAdjustedWork.VerzorgingId
};
}
I have a form that opens up a childform where two objects (2 times the same object of the type mentioned above) is being passed. I open up the form like this:
//my selected Record
Record rec = DateGridAdjustedWorks.ActiveRecord;
AangepastWerk AWorkObject = (AangepastWerk)((DataRecord)rec).DataItem;
AangepastWerk AWorkObjectBackup = _Vm.CloneAdjustedWork(AWorkObject);
WindowModifyAdjustedWork windowForModify = new WindowModifyAdjustedWork(AWorkObject,AWorkObjectBackup, true);
windowForModify.Closing += new CancelEventHandler(OnModifyAWClosing);
windowForModify.ShowDialog();
In that childform I set the first object as DataContext. _adjustedWork and _adjustedWorkCopy are properties of the form
_adjustedWork = pAdjustedWork;
GridAdjustedWork.DataContext = AdjustedWork;
_adjustedWorkCopy = pAdjustedWorkCopy;
The Issue:
In the form i have the ability to alter the object while retaining the original object. the user can see the originalobject, so he has the possibilities to keep track of the changes (request by the user) BUT if i change something in my _adjustedWork (the object that is my datacontext) then my _adjustedWorkCopy (without any actions performed upon it in my code-behind) is changed aswell. My question to you bright minds is: Why does this happen and how do i work around it? What am i missing here (probably something very basic)?

I always do deep cloning with serializing to json.
In example with Servicestack you can:
var json = myObject.ToJson();
var clonedObject = json.FromJson<MyObject>();
return clonedObject;
Maybe this can help.

Found the reason why the Cloned Object recieved the changes as well
public AangepastWerk CloneAdjustedWork(AangepastWerk pAdjustedWork)
{
return new AangepastWerk()
{
AangepastWerkID = pAdjustedWork.AangepastWerkID,
ArbeidsOngeval = pAdjustedWork.ArbeidsOngeval,
DatumCreatie = pAdjustedWork.DatumCreatie,
DatumLaatsteWijziging = pAdjustedWork.DatumLaatsteWijziging,
DatumOngeval = pAdjustedWork.DatumOngeval,
GewijzigdDoor = pAdjustedWork.GewijzigdDoor,
NietErkend = pAdjustedWork.NietErkend,
Stamnummer = pAdjustedWork.Stamnummer,
Verzorging = pAdjustedWork.Verzorging, <------------ Issue lies here
VerzorgingId = pAdjustedWork.VerzorgingId
};
}
pAdjustedWork.Verzorging is an object in this case. I needed to clone this object aswell.I assumed (incorrectly) that cloning as above mentionned would create a new separate 'VerzorgingsObject'.
The solution to my problem is:
MedicalCare_VM mcare_VM = new MedicalCare_VM();
return new AangepastWerk()
{
AangepastWerkID = pAdjustedWork.AangepastWerkID,
ArbeidsOngeval = pAdjustedWork.ArbeidsOngeval,
DatumCreatie = pAdjustedWork.DatumCreatie,
DatumLaatsteWijziging = pAdjustedWork.DatumLaatsteWijziging,
DatumOngeval = pAdjustedWork.DatumOngeval,
GewijzigdDoor = pAdjustedWork.GewijzigdDoor,
NietErkend = pAdjustedWork.NietErkend,
Stamnummer = pAdjustedWork.Stamnummer,
Verzorging = mcare_VM.CloneMedicalCare(pAdjustedWork.Verzorging),
VerzorgingId = pAdjustedWork.VerzorgingId
};
Cloning in:
Verzorging = mcare_VM.CloneMedicalCare(pAdjustedWork.Verzorging)
uses the same logic as mentioned before (copying every field).

Related

Sabre Web Services .NET API Examples that aren't MVC?

This is pretty general, but I'm having a hell of a time figuring out how to consume some of the more complicated Sabre APIs.
I have built working .NET proxy classes in C# using the WSDL for the basic APIs (CreateSession, CloseSession) but for the more complicated APIs I have a really hard time parsing out the complicated XML schema to figure out which methods to call in my program.
Are there any other .NET resources/examples out there that aren't wrapped up in MVC like the code example that Sabre posted on GitHub?
I'm trying to figure out how to use APIs like OTA_AirPriceLLSRQ and TravelItineraryReadRQ.
Thanks in advance for any help!
As I mentioned on the comments, you should not focus on the actual MVC wrapping, as you'll be mainly putting stuff in the Model, or actually you'll put this somewhere else and consume it in the model.
Anyway, just for you to have as example, here's a VERY generic BFM (BargianFinderMax) class. With this approach it's required to create an instance, and after calling the Execute method it stores the response in the instance.
I hope it helps.
using BargainFinderMaxRQv310Srvc;
using System;
using System.IO;
namespace ServicesMethods
{
public class BFM_v310
{
private BargainFinderMaxService service;
private OTA_AirLowFareSearchRQ request;
public OTA_AirLowFareSearchRS response;
public BFM_v310(string token, string pcc, string convId, string endpoint)
{
//MessageHeader
MessageHeader mHeader = new MessageHeader();
PartyId[] pId = { new PartyId() };
pId[0].Value = "SWS";
From from = new From();
from.PartyId = pId;
To to = new To();
to.PartyId = pId;
mHeader.Action = "BargainFinderMaxRQ";
mHeader.Service = new Service()
{
Value = mHeader.Action
};
mHeader.ConversationId = convId;
mHeader.CPAId = pcc;
mHeader.From = from;
mHeader.To = to;
mHeader.MessageData = new MessageData()
{
Timestamp = DateTime.UtcNow.ToString()
};
//Security
Security security = new Security();
security.BinarySecurityToken = token;
//Service
service = new BargainFinderMaxService();
service.MessageHeaderValue = mHeader;
service.SecurityValue = security;
service.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Soap11;
service.Url = endpoint;
createRequest(pcc);
}
private void createRequest(string pcc)
{
request = new BargainFinderMaxRQv310Srvc.OTA_AirLowFareSearchRQ();
request.AvailableFlightsOnly = true;
request.Version = "3.1.0";
request.POS = new SourceType[1];
SourceType source = new SourceType();
source.PseudoCityCode = pcc;
source.RequestorID = new UniqueID_Type();
source.RequestorID.ID = "1";
source.RequestorID.Type = "1";
source.RequestorID.CompanyName = new CompanyNameType();
source.RequestorID.CompanyName.Code = "TN";
source.RequestorID.CompanyName.CodeContext = "Context";
request.POS[0] = source;
OTA_AirLowFareSearchRQOriginDestinationInformation originDestination = new OTA_AirLowFareSearchRQOriginDestinationInformation();
originDestination.OriginLocation = new OriginDestinationInformationTypeOriginLocation();
originDestination.OriginLocation.LocationCode = "BCN";
originDestination.DestinationLocation = new OriginDestinationInformationTypeDestinationLocation();
originDestination.DestinationLocation.LocationCode = "MAD";
originDestination.ItemElementName = ItemChoiceType.DepartureDateTime;
originDestination.Item = "2017-09-10T12:00:00";
originDestination.RPH = "1";
request.OriginDestinationInformation = new OTA_AirLowFareSearchRQOriginDestinationInformation[1] { originDestination };
request.TravelerInfoSummary = new TravelerInfoSummaryType()
{
AirTravelerAvail = new TravelerInformationType[1]
};
request.TravelerInfoSummary.AirTravelerAvail[0] = new TravelerInformationType()
{
PassengerTypeQuantity = new PassengerTypeQuantityType[1]
};
PassengerTypeQuantityType passenger = new PassengerTypeQuantityType()
{
Quantity = "1",
Code = "ADT"
};
request.TravelerInfoSummary.AirTravelerAvail[0].PassengerTypeQuantity[0] = passenger;
request.TravelerInfoSummary.PriceRequestInformation = new PriceRequestInformationType();
request.TravelerInfoSummary.PriceRequestInformation.CurrencyCode = "USD";
//PriceRequestInformationTypeNegotiatedFareCode nego = new PriceRequestInformationTypeNegotiatedFareCode();
//nego.Code = "ABC";
//request.TravelerInfoSummary.PriceRequestInformation.Items = new object[1] { nego };
request.TPA_Extensions = new OTA_AirLowFareSearchRQTPA_Extensions();
request.TPA_Extensions.IntelliSellTransaction = new TransactionType();
request.TPA_Extensions.IntelliSellTransaction.RequestType = new TransactionTypeRequestType();
request.TPA_Extensions.IntelliSellTransaction.RequestType.Name = "50ITIN";
}
public bool Execute()
{
response = service.BargainFinderMaxRQ(request);
return response.PricedItinCount > 0;
}
}
}
My advice is you should add separate models which are built based on Sabre models, and which flatten the whole structure.
For example, TravelItineraryReadRS is a quite complicated document. Using it properties in your program is a real "pain", because every time you need to remember the whole path that leads to to specific information (like, "what is passenger type for PersonName of NameNumber 01.01?").
I suggest you have dedicated model (let's name it Reservation), which have all information that you will need later in your application, extracted from TravelItineraryReadRs.
In order to achieve this you need a dedicated converter which will make convert TravelItineraryReadRs model into Reservation model. Now, inside Reservation model you could have list of Passenger models, which have in on place all important information (NameNumber, PassengerType, SSR codes, etc).
This improves readability and as a bonus you decouple your application from Sabre (imagine, one day someone asks "can we switch from Sabre to Amadeus?" - if you use dedicated models the answer is "yes". If you don't have, then the answer is "probably yes, but it will take 6-9 months).

How to create New EPT by using CSOM

I try to create a new EPT (project server 2013) using C# CSOM library.
But It has following error occurred.
"PJClientCallableException: EnterpriseProjectTypeInvalidCreatePDPUid"
Couple of article tell to change the "IsCreate=true". But it does not success for me. Here is the code what I have done.
public void CreateEnterpriseProjectType(Guid eptGuid, string eptName, string eptDescription)
{
ProjectContext pwaContext = new ProjectContext(this.PWA_URL);
EnterpriseProjectTypeCreationInformation eptData = new EnterpriseProjectTypeCreationInformation();
eptData.Id = eptGuid;
eptData.Name = eptName;
eptData.Description = eptDescription;
eptData.IsDefault = false;
eptData.IsManaged = true;
eptData.WorkspaceTemplateName = "PROJECTSITE#0";
eptData.ProjectPlanTemplateId = Guid.Empty;
eptData.WorkflowAssociationId = Guid.Empty;
eptData.Order = 4;
List<ProjectDetailPageCreationInformation> projectDetailPages = new
List<ProjectDetailPageCreationInformation>() {
new ProjectDetailPageCreationInformation() {
Id = pwaContext.ProjectDetailPages[1].Id, IsCreate = true }
};
eptData.ProjectDetailPages = projectDetailPages;
pwaContext.Load(pwaContext.EnterpriseProjectTypes);
pwaContext.ExecuteQuery();
EnterpriseProjectType newEpt = pwaContext.EnterpriseProjectTypes.Add(eptData);
pwaContext.EnterpriseProjectTypes.Update();
pwaContext.ExecuteQuery();
}
Can anyone explain the issue or provide the working code part.
I would like to suggest the following:
Define an enterprise project type:
string basicEpt = "Enterprise Project"; // Basic enterprise project type.
int timeoutSeconds = 10; // The maximum wait time for a queue job, in seconds.
And then, when you create the new project, work like this:
ProjectCreationInformation newProj = new ProjectCreationInformation();
newProj.Id = Guid.NewGuid();
newProj.Name = "Project Name";
newProj.Description = "Test creating a project with CSOM";
newProj.Start = DateTime.Today.Date;
// Setting the EPT GUID is optional. If no EPT is specified, Project Server
// uses the default EPT.
newProj.EnterpriseProjectTypeId = GetEptUid(basicEpt);
PublishedProject newPublishedProj = projContext.Projects.Add(newProj);
QueueJob qJob = projContext.Projects.Update();
// Calling Load and ExecuteQuery for the queue job is optional.
// projContext.Load(qJob);
// projContext.ExecuteQuery();
JobState jobState = projContext.WaitForQueue(qJob, timeoutSeconds);
When the last line of that piece of code ends, the project must be created and published in order to define tasks or whatever.
I don't know what is happening to your code, seems great.
Hope it helps to you,

Convert identical objects from different namespaces?

These are the errors:
Error 1 Cannot implicitly convert type 'Plantool.xRoute.Point' to 'Plantool.xMap.Point'
Error 2 Cannot implicitly convert type 'Plantool.xRoute.Point' to 'Plantool.xMap.Point'
Error 3 Cannot implicitly convert type 'Plantool.xRoute.LineString' to 'Plantool.xMap.LineString'
I have this code which comes with a namespace.
using Plantool; //Contains xMap, xServer, xLocate
And this is the function in question.
/* createMap()
* Input: WaypointDesc[], Route
* Output: string mapURL
* Edited 21/12/12 - Davide Nguyen
*/
private static string createMap(xRoute.WaypointDesc[] waypointDesc, xRoute.Route route)
{
#region boundingBox
// Set boundingBox fand use corners from the calculated route
xMap.BoundingBox boundingBox = new xMap.BoundingBox();
boundingBox.leftTop = route.totalRectangle.rightTop;
boundingBox.rightBottom = route.totalRectangle.leftBottom;
#endregion
#region mapParams
// Build mapParams
xMap.MapParams mapParams = new xMap.MapParams();
mapParams.showScale = true;
mapParams.useMiles = false;
#endregion
#region imageInfo
// Create imageInfo and set the frame size and image format. NOTE: 1052; 863
xMap.ImageInfo imageInfo = new xMap.ImageInfo();
imageInfo.format = xMap.ImageFileFormat.PNG;
imageInfo.height = 1052;
imageInfo.width = 863;
imageInfo.imageParameter = "";
#endregion
#region layers
// Create a line from the calculated route
xMap.LineString[] lineStrings = new xMap.LineString[] { route.polygon };
xMap.Lines[] lines = new xMap.Lines[1];
xMap.LineOptions options = new xMap.LineOptions();
xMap.LinePartOptions partoptions = new xMap.LinePartOptions();
partoptions.color = new xMap.Color();
partoptions.visible = true;
partoptions.width = -10;
options.mainLine = partoptions;
lines[0] = new xMap.Lines();
lines[0].wrappedLines = lineStrings;
lines[0].options = options;
// Define customLayer that contains the object lines and set layers.
xMap.CustomLayer customLayer = new xMap.CustomLayer();
customLayer.visible = true;
customLayer.drawPriority = 100;
customLayer.wrappedLines = lines;
customLayer.objectInfos = xMap.ObjectInfoType.NONE;
customLayer.centerObjects = true;
xMap.Layer[] layers = new xMap.Layer[] { customLayer };
#endregion
#region includeImageInResponse
// Set argument includeImageInResponse to false (default).
Boolean includeImageInResponse = false;
#endregion
// Return object map using the following method.
xMap.Map map = xMapClient.renderMapBoundingBox(boundingBox, mapParams, imageInfo, layers, includeImageInResponse, null);
// Retrieve the image
string result = "http://" + map.image.url;
// Return the drawn map
return result;
}
The problem lies with the boundingBox object and the lineString object. route.totalRectangle contains a Point object from the xRoute namespace which is identical to that of xMap. Is there anyway to copy or convert it?
This issue does not seem to happen in java examples, but it does in C#. I am sure that if I can solve this error, the other ones will be solved aswell. I have searched my ass off on the API, but it may help you:
xMap:
http://xserver.ptvgroup.com/fileadmin/files/PTV-COMPONENTS/DeveloperZone/Documents/PTV_xServer/API/xMapAPI/pages/apidoc.html
xRoute: http://xserver.ptvgroup.com/fileadmin/files/PTV-COMPONENTS/DeveloperZone/Documents/PTV_xServer/API/xRouteAPI/pages/apidoc.html
Still digging myself.
In C# you cannot convert from one type to another, even if they are for all purposes identical, without copying all the properites, etc. unless an implicit conversion exists.
So you can either write a implicit conversion opertor as shown in link above or you could use a tool like AutoMapper to copy between the two objects
I have found another solution for this issue in the meanwhile whilst randomly playing with the code and the API and this is a partial solution for two of the errors by copying over the well known text values from one object to another. Hopefully I can do the same for the linestring part. I am posting this just incase anyone else comes across this and finds it a usefull solution. New code region below.
// Set boundingBox fand use corners from the calculated route
xMap.BoundingBox boundingBox = new xMap.BoundingBox();
xMap.Point rightTop = new xMap.Point();
rightTop.wkt = route.totalRectangle.rightTop.wkt;
xMap.Point leftBottom = new xMap.Point();
leftBottom.wkt = route.totalRectangle.leftBottom.wkt;
boundingBox.leftTop = rightTop;
boundingBox.rightBottom = leftBottom;
EDIT: Same solution for the linestrings.
// Solution: Cannot implicitly conver ttype xRoute.LineString to xMap.LineString
xMap.LineString maproute = new xMap.LineString();
maproute.wkt = route.polygon.wkt;
// Create a line from the calculated route
xMap.LineString[] lineStrings = new xMap.LineString[] { maproute };
Thanks for the help, I hope someone might find this solution usefull aswell.
Review this for your own purposes... but one option is to use a JSON Parser to serialize one class into JSON, then to deserialize it back into a different class. Short and simple answer, but if all you are looking for is to grab properties from Contoso.Project.UrMom, and transfer them directly to Albiet.Project.UrMom, it works well.
I've found this other alternative that is based on serialization of the objects. As far as I'm concerned it has the disadvantage of accessing the disk.
How did you create the client classes from the WSDL's?
I prefer to create them via command line:
WSDL /sharetypes /out:"XServer.cs" /namespace:"Plantool"
"https://xroute-eu-n-test.cloud.ptvgroup.com/xlocate/ws/XLocate?WSDL"
"https://xroute-eu-n-test.cloud.ptvgroup.com/xroute/ws/XRoute?WSDL"
"https://xroute-eu-n-test.cloud.ptvgroup.com/xtour/ws/XTour?WSDL"
/sharetypes ensures that classes such as Point will be merged intoa single shared class
This also works fine with the xServer2 API and it's WSDLs.

How to save changes in Linq-to-SQL?

So, here is my hopefully unique spin on this common problem.
I do my query, get my objects then pass the object into a form where it populates the form with the data from the object (this is not passed in by reference).
I then edit the values of the object that was queried (via the form) and then return a new object constructed from the values in the form.
I then want to update this to the database. Attach does nothing (runs but does not update). SubmitChanges also does nothing (and both do nothing when used together).
What am I missing?
Update: here is the code I am using:
// In constructor
_dataMap = new DataMapDataContext();
_addresses = _dataMap.AddressItems
.Where(address => address.InsertUserName == _currentUser.Name).ToList();
public void EditButtonClick()
{
using (AddAddressForm form = new AddAddressForm(_addresses[_currentAddress]))
{
form.Text = "Edit Address";
if (DialogResult.OK == form.ShowDialog())
{
_addresses[_currentAddress] = form.Item;
_dataMap.SubmitChanges();
DisplayItem();
}
}
}
You'll need to get the record from the database, update it's values and then call SubmitChanges()
using(MyDataContext db = new MyDataContext())
{
// get the record
Product dbProduct = db.Products.Single(p => p.ID == 1);
// set new values
dbProduct.Quantity = 5;
dbProduct.IsAvailable = false;
// save them back to the database
db.SubmitChanges();
}
Turns out I was doing almost everything right.
I just needed to pass in the object I was editing by reference. That way when it got changed, it was not a new object that was returned, but the same one (that Linq-to-SQL already knew about.)
These are the two lines from the code above that got changed:
AddressItem itemToEdit = _addresses[_currentAddress];
using (AddAddressForm form = new AddAddressForm(ref itemToEdit))

How To add another constructor with parameter in linq class(Table)

I am using LINQ to SQL in an ASP.NET project. While inserting the table I need to convert the values to the particular table object and I need to insert.
For that I created a new constructor in that table with parameter so that I can assign my value to that table object , the assign the functionality is working but while inserting (obj.TS_Questions.InsertOnSubmit(mytableobject);) I get null exception.
my code::
default constructor for my table
public TS_Question()
{
this._TS_Options = new EntitySet<TS_Option>(new Action<TS_Option>(this.attach_TS_Options), new Action<TS_Option>(this.detach_TS_Options));
this._TS_QuestGroups = new EntitySet<TS_QuestGroup>(new Action<TS_QuestGroup>(this.attach_TS_QuestGroups), new Action<TS_QuestGroup>(this.detach_TS_QuestGroups));
this._TS_QuestRecords = new EntitySet<TS_QuestRecord>(new Action<TS_QuestRecord>(this.attach_TS_QuestRecords), new Action<TS_QuestRecord>(this.detach_TS_QuestRecords));
this._TS_Admin = default(EntityRef<TS_Admin>);
this._TS_LevelType = default(EntityRef<TS_LevelType>);
this._TS_OptionTypeLT = default(EntityRef<TS_OptionTypeLT>);
OnCreated();
}
constructor created by me
public TS_Question(Guid Quest_QuestIDBL, string Quest_NameBL, Nullable<Guid> Quest_OptionTypeIDBL, Guid Quest_AdminIDBL, Guid Ques_LevelIDBL, int Quest_TimeBL, int Quest_MarkBL, string Qest_ExplanationBL, Nullable<bool> Qest_IsMultipleAnswerBL)
{
this._TS_Options = new EntitySet<TS_Option>(new Action<TS_Option>(this.attach_TS_Options), new Action<TS_Option>(this.detach_TS_Options));
this._TS_QuestGroups = new EntitySet<TS_QuestGroup>(new Action<TS_QuestGroup>(this.attach_TS_QuestGroups), new Action<TS_QuestGroup>(this.detach_TS_QuestGroups));
this._TS_QuestRecords = new EntitySet<TS_QuestRecord>(new Action<TS_QuestRecord>(this.attach_TS_QuestRecords), new Action<TS_QuestRecord>(this.detach_TS_QuestRecords));
this._TS_Admin = default(EntityRef<TS_Admin>);
this._TS_LevelType = default(EntityRef<TS_LevelType>);
this._TS_OptionTypeLT = default(EntityRef<TS_OptionTypeLT>);
OnCreated();
this._Quest_QuestID = Quest_QuestIDBL;
this._Quest_Name = Quest_NameBL;
if (Quest_OptionTypeIDBL != null)
{
this._Quest_OptionTypeID = Quest_OptionTypeIDBL;
}
this._Quest_AdminID = Quest_AdminIDBL;
this._Ques_LevelID = Ques_LevelIDBL;
this._Quest_Time = Quest_TimeBL;
this._Quest_Mark = Quest_MarkBL;
this._Qest_Explanation = Qest_ExplanationBL;
this._Qest_IsMultipleAnswer = Qest_IsMultipleAnswerBL;
}
Please help me out from this problem
Honestly, I haven't looked too deep, but it looks like that OnCreated is sitting a little far north... You probably want to call it after you're done setting up your variables. Other than that i'd say make sure you're properly initializing everything in the method calling the constructor.
You can call default constructor like this, it works fine for me:
public partial class MyClass
{
public MyClass(string fieldValue1,int fieldValue2)
: this()
{
this.field1= fieldValue1;
this.field2 = fieldValue2;
}
}
If this do the trick, you can read more about using contructors in C# here.

Categories