I have a quick question regarding LINQ and attributes in CRM. I am having some issue with this little piece of code that I am attempting to write.
//Create query to get the related regular rates
var rateres = from r in ServiceContext.CreateQuery("pafo_rate")
where r["pafo_assignmentid"].Equals(entity.Id)
select r;
//Exception Rate - excluding pto
// var eateres = from er in ServiceContext.CreateQuery("pafo_exceptionrate")
// where er["pafo_assignmentid"].Equals(entity.Id) && er["pafo_assignmentid"] != ""
// select er;
foreach (var r in rateres)
{
Entity e = (Entity)r;
// e["pafo_billrate"] = newbillupdate + payupdate;
// test = (decimal)e.Attributes["pafo_payrate"]; \\ <-- How do you fix?
// test = 6;
e["pafo_payrate"] = (newpayupdate + test);
// ServiceContext.Attach(e);
ServiceContext.UpdateObject(e);
ServiceContext.SaveChanges();
}
When the plugin fires I get a message along the lines of:
Microsoft.Xrm.Sdk.SaveChangesException: An error occured while
processing this request.
I think it has to do with the way I am assigning to variable. Any help would be greatly appreciated!
Related
I use an e-commerce SOAP API, forgive me if it's too confusing to answer. I just want to know if I'm just making a stupid mistake before I write a ticket to API maintainers.
public void WriteXML()
{
var results = GetProductsFromApi().results.ToList();
using (var file = File.Create(#"products.xml"))
{
var list = new List<Product>();
var writer = new XmlSerializer(typeof(List<Product>));
foreach (var result in results)
{
var newProduct = new Product
{
Id = result.productId,
Index = result.productDisplayedCode,
Stock = result.productStocksData.productStocksQuantities[0].productSizesData[0].productSizeQuantity,
IsIgnored = false,
IsInDelivery = false
};
list.Add(newProduct);
}
writer.Serialize(file, list);
}
}
I made a request to the API and I want to store it in a list, so each result gets serialized into an XML later. The code above works if I set Stock to something like Stock = 1, - however if left as it is, the program quits with Unhandled exception: System.IndexOutOfRangeException.
What's weird though is that if I do something similar to the following before building the Product object:
Console.WriteLine(result.productStocksData.productStocksQuantities[0].productSizesData[0].productSizeQuantity);
...I am met with a correct API response.
I have no clue what's going on. I tried checking if the result is null before constructing Product, but it didn't help. The whole exception is so confusing to me I don't really know where to start looking.
Edit: Using Fildor's proposed code, I wrote this:
float? lol = result.productStocksData.productStocksQuantities.FirstOrDefault().productSizesData.FirstOrDefault()?.productSizeQuantity ?? null; //doesn't actually change anything if it's null or 0
if (lol.GetValueOrDefault() == 0) {
lol = 1;
};
var newProduct = new Product
{
Id = result.productId,
Index = result.productDisplayedCode,
Stock = (float)lol,
IsIgnored = false,
IsInDelivery = false
};
Console.WriteLine("Processed product has a stock of " + lol);
list.Add(newProduct);
It now results in System.NullReferenceException. It responds with actual stock size, and said error appears after.
I am trying to get the guid value of a combobox.
Here be my code:
private void PopulateComboBox()
{
using (var ent = new SuburbanPortalEntities())
{
var qry = (from x in ent.Corporations
select x).ToList();
comboBox_CompanyId.DataSource = qry;
comboBox_CompanyId.DisplayMember = "CompanyCode";
comboBox_CompanyId.ValueMember = "CorporationId";
}
}
And I'm referencing it here:
private void comboBox_CompanyId_SelectedIndexChanged(object sender, EventArgs e)
{
using (var ent = new SuburbanPortalEntities())
{
var corpid = ((Corporation) comboBox_CompanyId.SelectedValue).CorporationId;
// ^^ this is where the exception occurs
//var corpid = (Guid) comboBox_CompanyId.SelectedValue;
// ^^ tried this but the form initialization gives an exception
if (corpid == Guid.Empty) return;
var qry = (from x in ent.Trucks
where x.CorporationId == corpid
orderby x.TruckNumber
select x).ToList();
if (!qry.Any()) return;
comboBox_TruckNumber.DataSource = qry;
comboBox_TruckNumber.DisplayMember = "TruckNumber";
comboBox_TruckNumber.ValueMember = "TruckId";
}
The first time I get the corpid, during the form initialization, it works fine. When I change the value in the combobox, it gives me this error:
Unable to cast object of type 'System.Guid' to type
TruckTransactions.data.Corporation'.
I'm not sure I understand why the type in my combobox is changing.
Here, you populate comboBox_CompanyId with Corporations:
comboBox_CompanyId.DataSource = qry;
comboBox_CompanyId.DisplayMember = "CompanyCode";
Here, you tell it to use the CorporationId property of the selected Corporation (a Guid) as the SelectedValue:
comboBox_CompanyId.ValueMember = "CorporationId";
Here, you take the SelectedValue, which you insisted must be a Guid, and you cast it to Corporation instead, with predictable results:
var corpid = ((Corporation) comboBox_CompanyId.SelectedValue).CorporationId;
Now, the way you could have diagnosed this was to put in a breakpoint and hover the mouse over comboBox_CompanyId.SelectedValue in the debugger, instead of asking strangers on the internet what's going on in the code running on your own desktop. Then you would have found that comboBox_CompanyId.SelectedValue was already the CorporationId you want.
tl;dr
var corpId = (Guid)comboBox_CompanyId.SelectedValue;
comboBox_CompanyId.SelectedItem is a Corporation.
Instead of
comboBox_CompanyId.SelectedValue
do
comboBox_CompanyId.SelectedItem
Problem solved.
Here is what happens
// here
var corpid = ((Corporation) comboBox_CompanyId.SelectedValue).CorporationId;
// comboBox_CompanyId.SelectedValue is already corporation id
// because you did this --> comboBox_CompanyId.ValueMember = "CorporationId";
// so you should be able to do
var corpid = (cast type)comboBox_CompanyId.SelectedValue;
// or, do what I said above
On another note, first set DisplayMember and ValueMember. Assign DataSource last - performance
I'm trying to parse an XML file from UN website (http://www.un.org/sc/committees/1267/AQList.xml) using c#.
There is one problem I'm constantly having with this file, and that's the number of child tags varies from one <.INDIVIDUAL.> tag to another. One example is <.FORTH_NAME.> child tag.
I've tried a number of different approaches, but somehow I always seem to be stuck with the same problem, and that's different number of child tags inside <.INDIVIDUAL.> tag.
What I'm trying to achieve is to collect all the tags and their values under one <.INDIVIDUAL.> tag, and then insert only those I want into my database. If a tag is missing, for example <.FOURTH_NAME.>, than I need to insert only first three names into the database, and skip the fourth.
I've tried using Linq to XML, and here are some examples:
XDocument xdoc = XDocument.Load(path);
var tags = (from t in xdoc.Descendants("INDIVIDUALS")
from a in t.Elements("INDIVIDUAL")
select new
{
Tag = a.Name,
val = a.Value
});
foreach (var obj in tags)
{
Console.WriteLine(obj.Tag + " - " + obj.val + "\t");
//insert SQL goes here
}
or:
but this one only collects non empty FOURTH_NAME tags...
var q = (from c in xdoc.Descendants("INDIVIDUAL")
from _1 in c.Elements("FIRST_NAME")
from _2 in c.Elements("SECOND_NAME")
from _3 in c.Elements("THIRD_NAME")
from _4 in c.Elements("FOURTH_NAME")
where _1 != null && _2 != null && _3 != null && _4 != null
select new
{
_1 = c.Element("FIRST_NAME").Value,
_2 = c.Element("SECOND_NAME").Value,
_3 = c.Element("THIRD_NAME").Value,
_4 = c.Element("FOURTH_NAME").Value
});
foreach (var obj in q)
{
Console.WriteLine("Person: " + obj._1 + " - " + obj._2 + " - " + obj._3 + " - " + obj._4);
//insert SQL goes here
}
Any ideas??
Instead of calling Value on the element, consider using a string cast. LINQ to XML safely returns null if the element doesn't exist. Try the following:
var data = XElement.Load(#"http://www.un.org/sc/committees/1267/AQList.xml");
var individuals = data.Descendants("INDIVIDUAL")
.Select(i => new {
First = (string)i.Element("FIRST_NAME"),
Middle = (string)i.Element("SECOND_NAME"),
Last = (string)i.Element("THIRD_NAME")
});
If you want to be more flexible and get all of the name fields, you can do something like the following. (I'll leave the process of grouping individuals as an additional homework assignment ;-)
data.Descendants("INDIVIDUAL").Elements()
.Where (i =>i.Name.LocalName.EndsWith("_NAME" ))
.Select(i => new { FieldName= i.Name.LocalName, Value=i.Value});
Why don't you use XmlSerializer and LINQ instead ?
As explained in this answer, generate your classes by pasting in a new CS file :
menu EDIT > Paste Special > Paste XML As Classes.
Then grab your data as easily as follows :
var serializer = new XmlSerializer(typeof (CONSOLIDATED_LIST));
using (FileStream fileStream = File.OpenRead(#"..\..\aqlist.xml"))
{
var list = serializer.Deserialize(fileStream) as CONSOLIDATED_LIST;
if (list != null)
{
var enumerable = list.INDIVIDUALS.Select(s => new
{
FirstName = s.FIRST_NAME,
SecondName = s.SECOND_NAME,
ThirdName = s.THIRD_NAME,
FourthName = s.FOURTH_NAME
});
}
}
You can then specify any predicate that better suits your needs.
Going this path will be a huge time-saver and less error-prone, no need to use strings to access fields, strong typing etc ...
I want to know the quickest and simplest way to sort the code shown below. Sorting from newRecord.AppCode would not be suitable as it will change the meaning of the output. So I need to sort every line from string outp. What would be the best way? Also I would like to make every row distinct. I beleive using LINQ would be very quick but I am not that great at it. Help appreciated. So close to getting it done! Note: Data is being pulled from a tsv. Using .net 3.5, visual studio 2008) Will mark answer as soon as I get progress. :)
while ((line = sr.ReadLine()) != null)
{
String[] splitted = line.Split('\t');
appcodes.Add(line);
Records newRecord = new Records();
newRecord.Server = splitted[0];
newRecord.Instance = splitted[1];
newRecord.AppCode = splitted[2];
newRecord.Database = splitted[3];
listrecords.Add(newRecord);
for (int i = 0; i < appcodes.Count(); i++)
{
if (newRecord.AppCode==appcodes[i].ToUpper())
{
String outp = newRecord.AppCode + " " + newRecord.Server + " " + newRecord.Instance + " " + newRecord.Database;
Console.WriteLine(outp);
}
}
}
have lists named Keepers and newkeepers. Was trying to do something like outp.sort() and outp.sort() but it doesnt work in strings. This is how I solved the problem.
Keepers.Add(outp);
Keepers.Sort();
newKeepers = Keepers.Distinct().ToList();
foreach (object o in newKeepers)
{
Console.WriteLine(o);
}
Console.ReadLine();
As you can see, newrecords contain different fields so I wrote a LINQ statement to solve the problem.
var sorted_list = (from r in newrecords
orderby r.AppCode, r.Server, r.Instance, r.Database
select r).Distinct().ToList();
var distinctSortedList = sorted_list.Distinct().ToList();
I know what index out of bounds is all about. When I debug I see why as well. basically what is happening is I do a filter on my database to look for records that are potential/pending. I then gather a array of those numbers send them off to another server to check to see if those numbers have been upgraded to a sale. If it has been upgraded to a sale the server responds back with the new Sales Order ID and my old Pending Sales Order ID (SourceID). I then do a for loop on that list to filter it down that specific SourceID and update the SourceID to be the Sales Order ID and change a couple of other values. Problem is is that when I use that filter on the very first one it throws a index out of bounds error. I check the results returned by the filter and it says 0. Which i find kind of strange because I took the sales order number from the list so it should be there. So i dont know what the deal is. Here is the code in question that throws the error. And it doesn't do it all the time. Like I just ran the code this morning and it didn't throw the error. But last night it did before I went home.
filter.RowFilter = string.Format("Stage = '{0}'", Potential.PotentialSale);
if (filter.Count > 0)
{
var Soids = new int[filter.Count];
Console.Write("Searching for Soids - (");
for (int i = 0; i < filter.Count; i++)
{
Console.Write(filter[i][1].ToString() + ",");
Soids[i] = (int)filter[i][1];
}
Console.WriteLine(")");
var pendingRecords = Server.GetSoldRecords(Soids);
var updateRecords = new NameValueCollection();
for (int i = 0; i < pendingRecords.Length; i++)
{
filter.RowFilter = "Soid = " + pendingRecords[i][1];
filter[0].Row["Soid"] = pendingRecords[i][0];
filter[0].Row["SourceId"] = pendingRecords[i][1];
filter[0].Row["Stage"] = Potential.ClosedWon;
var potentialXML = Potential.GetUpdatePotentialXML(filter[0].Row["Soid"].ToString(), filter[0].Row["Stage"].ToString());
updateRecords.Add(filter[0].Row["ZohoID"].ToString(), potentialXML);
}
if i'm counting right line 17 is the error where the error is thrown. pendingRecords is a object[][] array. pendingRecords[i] is the individual records. pendingRecords[i][0] is the new Sales OrderID (SOID) and pendingRecords[i][1] is the old SOID (now the SourceID)
Any help on this one? is it because i'm changing the SOID to the new SOID, and the filter auto updates itself? I just don't know
Well I ended up changing how it worked all together and it actually sorts it a bit nicer now. The code i am about to post has a bunch of hard coded numbers due to the structure of my table that is returned. Sorry about that. I have learned since then to not do that, but i am working on a different project now and will change that when I have to change the program. But here is the solution.
var potentials = Server.GetNewPotentials(); //loads all records from server
for (int i = 0; i < potentials.Length; i++)
{
var filter = AllPotentials.DefaultView;
var result1 = CheckSoidOrSource(potentials[i].Soid, true);
var result2 = CheckSoidOrSource(potentials[i].SourceID,false) ;
//This potential can't be found at all so let's add it to our table
if (result1+result2==0)
{
Logger.WriteLine("Found new record. Adding it to DataTable and sending it to Zoho");
AllPotentials.Add(potentials[i]);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
ZohoPoster posterInsert = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.insertRecords);
AllPotentials.Rows[index]["ZohoID"] = posterInsert.PostNewPotentialRecord(3, filter[0].Row);
}
//This potential is not found, but has a SourceId that matches a Soid of another record.
if (result1==0 && result2 == 1)
{
Logger.WriteLine("Found a record that needs to be updated on Zoho");
ZohoPoster posterUpdate = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.updateRecords);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
AllPotentials.Rows[index]["Soid"] = potentials[i].Soid;
AllPotentials.Rows[index]["SourceId"] = potentials[i].SourceID;
AllPotentials.Rows[index]["PotentialStage"] = potentials[i].PotentialStage;
AllPotentials.Rows[index]["UpdateRecord"] = true;
AllPotentials.Rows[index]["Amount"] = potentials[i].Amount;
AllPotentials.Rows[index]["ZohoID"] = posterUpdate.UpdatePotentialRecord(3, filter[0].Row);
}
}
AllPotentials.AcceptChanges();
}
private int CheckSoidOrSource(string Soid, bool checkSource)
{
var filter = AllPotentials.DefaultView;
if (checkSource)
filter.RowFilter = string.Format("Soid = '{0}' OR SourceId = '{1}'",Soid, Soid);
else
filter.RowFilter = string.Format("Soid = '{0}'", Soid);
return filter.Count;
}
basically what is happening is that i noticed something about my data when I filter it this way. The two results would only return the following results (0,0) (0,1) and (1,0) (0,0) means that the record doesn't exist at all in this table so I need to add it. (1,0) means that the Sales Order ID (Soid) matches another Soid in the table so it already exists. Lastly (0,1) means that the Soid doesn't exist in this table but i found a record that has the Soid as it's source...which to me means that the one that had it as a source has been upgraded from a potential to a sale, which in turn means i have to update the record and Zoho. This worked out to much less work for me because now I don't have to search for won and lost records, i only have to search for lost records. less code same results is always a good thing :)