LINQ to Sharepoint InsertOnSubmit Question - c#

For example I have a list called Product and it has 3 columns, ProductName (which is the Title), ProductPrice and ProductType.
ProductName is a string
ProductPrice is a currency (double)
ProductType is a LookUp on ProductTypes List
Normally this is easy for me if it does not contain a LookUp column, but I dont know how to deal with look up columns when Inserting.
I had tried this one but it returns an error Specified cast is not valid.
Here is the current code
EntityList<ProductTypeItem> ProductTypes = dc.GetList<ProductTypeItem>("ProductType");
ProductItem newProduct = new ProductItem();
newProduct.Title = txtProductName.Text;
newProduct.ProductPrice = double.Parse(txtProductPrice.Text);
newProduct.ProductType = (from a in ProductTypes where a.Title == ddProductType.SelectedItem.Text select a).FirstOrDefault();
dc.Product.InsertOnSubmit(newProduct);
dc.SubmitChanges();
What would I do with the newProduct.ProductType as here is where the error occurs.
Please note that the ddProductType DataSource is the ProductType List and uses Title in its DataTextField and DataValueField

This might help you out. The first example explains how the insert should work with links to existing data. This sample code should give you enough hints to help you fix your problem:
AdventureWorksDataContext db = new AdventureWorksDataContext();
// LINQ query to get StateProvince
StateProvince state = (from states in db.StateProvinces
where states.CountryRegionCode == "AU" && states.StateProvinceCode == "NSW"
select states).FirstOrDefault();
// LINQ function to get AddressType
AddressType addrType = db.AddressTypes.FirstOrDefault(s => s.Name == "Home");
Customer newCustomer = new Customer()
{
ModifiedDate= DateTime.Now,
AccountNumber= "AW12354",
CustomerType='I',
rowguid= Guid.NewGuid(),
TerritoryID= state.TerritoryID // Relate record by Keys
};
Contact newContact = new Contact()
{
Title = "Mr",
FirstName = "New",
LastName = "Contact",
EmailAddress = "newContact#company.com",
Phone = "(12) 3456789",
PasswordHash= "xxx",
PasswordSalt= "xxx",
rowguid = Guid.NewGuid(),
ModifiedDate = DateTime.Now
};
Individual newInd = new Individual()
{
Contact= newContact, // Relate records by objects (we dont actually know the Keys for the new records yet)
Customer= newCustomer,
ModifiedDate= DateTime.Now
};
Address newAddress = new Address()
{
AddressLine1= "12 First St",
City= "Sydney",
PostalCode= "2000",
ModifiedDate=DateTime.Now,
StateProvince= state,
rowguid = Guid.NewGuid()
};
// Link our customer with their address via a new CustomerAddress record
newCustomer.CustomerAddresses.Add(new CustomerAddress() { Address = newAddress, Customer = newCustomer, AddressType = addrType, ModifiedDate = DateTime.Now, rowguid = Guid.NewGuid() });
// Save changes to the database
db.SubmitChanges();

I'm not familiar with Linq to SharePoint, but I assume it is similar to the Client Object model. If so, you'll need to use a FieldLookupValue for the value of newProduct.ProductType and use the ID of the lookup as the value:
newProduct.ProductType = new FieldLookupValue { LookupId = 1 };
This means you'll need to have access to the lookup value's ListID in your ProductTypes query.

The way you are doing seems correct to me. It is the same way I've been doing it with success. Are you sure the problem is the lookup column? Is double the correct type for the currency? Often currency is saved as a decimal, not a double.
By the way, you don't have to get the Entitylist separately. SPMetal makes the shorthand dc.ProductType, like the one you already use in the insertOnSubmit. No idea why all examples do this...
Try to split the assignments a bit and debug again. See if everything is the way it should be.
ProductItem newProduct = new ProductItem();
string selectedProductType = ddProductType.SelectedItem.Text;
ProductTypeItem productType = (from a in dc.ProductType
where a.Title == selectedProductType
select a).FirstOrDefault();
newProduct.Title = txtProductName.Text;
newProduct.ProductPrice = decimal.Parse(txtProductPrice.Text);
newProduct.ProductType = productType;
dc.Product.InsertOnSubmit(newProduct);
dc.SubmitChanges();
Hope this helps

It works now and here is the solution
EntityList<Item> ProductTypes = dc.GetList<Item>("ProductType");
Item oProductType = (from a in ProductTypes where a.Title == ddProductType.SelectedItem.Text select a).FirstOrDefault();
ProductItem newProduct = new ProductItem();
newProduct.Title = txtProductName.Text;
newProduct.ProductPrice = double.Parse(txtProductPrice.Text);
newProduct.ProductType = (ProductTypeItem)oProductType;
dc.Product.InsertOnSubmit(newProduct);
dc.SubmitChanges();
The only thing I changed is to initialize the the Product Type as Item rather than ProductTypeItem, then cast it to ProductTypeItem now it works

The LINQ to SharePoint generated code is out of sync with you list. Re-generate the list and it will work -Paul Beck

Related

Search a Json object array- List vs Dictionary

I deserialized a JsonResponse using the below code.
var data = (JObject)JsonConvert.DeserializeObject(jsonResponse);
I got the response string which looks something like this
{
"results":[
{
"url":"tickets/2063.json",
"id":20794,
"subject":"Device not working",
"created_date": "2018-01-10T13:03:23Z",
"custom-fields":[
{
"id":25181002,
"value":34534
},
{
"id":2518164,
"value":252344
}
]
}
]
}
My objective is to read certain fields in this array of json objects and insert into a database. The fields i require are id, subject, created_date, member_id.
The member id is part of the custom fields. member_id is the value where id=2518164. I've used List to store this, can you let me know if List or Dictionary is better for this case. How to implement a dictionary
var data = (JObject)JsonConvert.DeserializeObject(jsonResponse);
var tickets = data["results"].ToList();
foreach (var ticketItem in tickets){
Int64? ticketFormId = ticketItem["id"].Value<Int64>();
string subject = ticketItem["subject"].Value<string>();
DateTime createdDate = ticketItem["created_date"].Value<DateTime>();
//Do you think for the next step a dictionary is better or a List is better, since I want to search for a particular id=2518164
var fieldsList = ticketItem["fields"].ToList();
foreach(var fieldItem in fieldList){
Int64? fieldId = fieldItem["id"].Value<Int64>();
if(fieldId!=null && fieldId == 2518164){
memberId = fieldItem["value"].Value<string>();
}
}
}
If you're next step to insert them all into the database, just store them into a list. A dictionary is only useful to search the item by a key.
You can also use linq to process the json in a simpler way:
var tickets = JObject.Parse(jsonResponse)["results"]
.Select(ticket => new
{
Id = (long)ticket["id"],
Subject = (string)ticket["subject"],
CreatedDate = (DateTime)ticket["created_date"],
MemberId = (long)ticket["custom-fields"]
.FirstOrDefault(cf => (int)cf["id"] == 2518164)
?["value"],
})
.ToList();

Given a list of several of the same object, group and combine them based on field value

Sorry for the incoherent title. I don't know how to concisely explain my problem, which is why I didn't really know how to look it up. I'll explain using an example...
Let's say I have a class:
public class cas
{
public string name { get; set; }
public int num { get; set; }
}
With that class, I make several objects and stick them into a list. For the sake of example, I will make 4:
var list = new List<cas>
{
new cas { name = "firstname", num = 1 },
new cas { name = "firstname", num = 2 },
new cas { name = "lastname", num = 3 },
new cas { name = "lastname", num = 4 }
};
Is there a way to take this List and combine any objects with the same name field?
So, the new list would be 1 object with:
name = "firstname", num = 3,
name = "lastname", num = 7
There's the obvious "long" way to do it, but it would be clunky and expensive (go through the list several times to find like-objects). I was wondering if I was missing any clean way of doing it. I intentionally made a simple example so that the answer would be a proof of concept rather than writing my code for me. My actual problem is more complex than this, but I can't figure out this one aspect of it.
Using Linq, you have a GroupBy Method and a Select Method:
list = list.GroupBy(x=> x.name)
.Select(x=> new cas() { name = x.Key, num = x.Sum(y=> y.num) }).ToList();
Or using Elegant query-syntax:
list = (from item in list
group item by item.name into grouping
select new cas()
{
name = grouping.Key,
num = grouping.Sum(x => x.num)
}).ToList();
Note that to use these methods, you have to add using System.Linq at the top of your source file.
You can use linq, you would have to group them on name property and then sum on the num property of each group like:
var result = list.GroupBy(x=>x.name)
.Select(g=> new cas
{
name = g.Key,
num = g.Sum(x=>x.num)
});

How to cast a type to specific class in c# 4.0 after querying LINQ to Object

i have a list of customer and later i query that list of customer to extract one customer data based on country code. how to achieve easily this task. here is my code snippet
public class Customer
{
public string Name
{ get; set; }
public double Salary
{ get; set; }
public string CountryCode
{ get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
List<Customer> oCust = new List<Customer>();
oCust.Add(new Customer { Name = "Tridip", Salary = 200, CountryCode = "GB" });
oCust.Add(new Customer { Name = "Ari", Salary = 200, CountryCode = "US" });
oCust.Add(new Customer { Name = "Dib", Salary = 200, CountryCode = "CA" });
Customer oCustomer = oCust.Where(x => x.CountryCode == "US");
}
this line is giving error Customer oCustomer = oCust.Where(x => x.CountryCode == "US");
i could follow this below approach to solve it
var oCustomer = oCust.Where(x => x.CountryCode == "US");
foreach (var item in oCustomer)
{
Customer _Cust = new Customer();
_Cust.Name = item.Name;
_Cust.Salary = item.Salary;
_Cust.CountryCode = item.CountryCode;
}
but i like to know is there any other way around to get one customer data after querying list.
please let me know with sample code. also discuss how to solve the above scenario using auto mapper with sample code.
thanks
Use .FirstOrDefault() to get the first element matching your Where(), or null when none match:
var oCustomer = oCust.Where(x => x.CountryCode == "US").FirstOrDefault();
also discuss how to solve the above scenario using auto mapper with sample code.
You've done this under various of your questions: "Here is my question, oh and please explain this related concept to me with sample code".
This is not how Stack Overflow works. Search the web for automapper, find their Getting Started page and ask a new question if you can't figure out how to use it.
The thing is that Where returns a collection of entries, but you only want one (which one?). You could solve this like
Customer oCustomer = oCust.Where(x => x.CountryCode == "US").FirstOrDefault();
but this makes no representation about which one is chosen. It just picks the first it finds or returns null.
You should really introduce a way to identify customers uniquely or operate on collections, as there may be more than once customer from the US

Seeding data in Configuration.cs, creating duplicate data with AddOrUpdate

I am using Migrations in an MVC 4 EF5 application in Visual Studio 2012 Express with SQL Server 2012 Express, using Code First.
I use the Seed method in configuration.cs, firstly creating a Tags table. When I execute 'Update-Database -verbose -force' from Package Manager, it works correctly and doesn't create duplicate tags - and re-creates them if deleted:
db.Tags.AddOrUpdate(
t => t.Name,
new Tag { Name = "Bakery", NamePlural = "Bakeries" },
new Tag { Name = "Bar", NamePlural = "Bars" },
new Tag { Name = "Bookshop", NamePlural = "Bookshops" }
);
db.SaveChanges();
I then try and add related Places data:
db.Places.AddOrUpdate(
p => p.Name,
new Place
{
Name = "Shoreditch Grind",
URL = "shoreditch-grind-cafe",
Address = "213 Old St",
City = "London",
PostCode = "EC1V 9NR",
Website = "www.shoreditchgrind.com",
Phone = "020 7490 0101",
About = "Good coffee on the Silicon Roundabout",
Image = "noimage.png",
Tag = db.Tags.Single(t => t.Name == "Bar")
},
new Place
{
Name = "The Old Blue Last",
URL = "old-blue-last-pub",
Address = "38 Great Eastern St",
City = "London",
PostCode = "EC2A 3ES",
Website = "www.theoldbluelast.com",
Phone = "020 7739 7033",
About = "Pub of Vice Magazine",
Image = "noimage.png",
Tag = db.Tags.Single(t => t.Name == "Bakery")
}
);
This however creates duplicates, adding all the places again every time I execute 'Update-Database -verbose -force'
I'm new to MVC - and I also don't fully understand what this does:
p => p.Name,
I have a feeling perhaps I should be manually adding ID values to each object?
How can I run this without creating duplicate Places?
It would also be useful to be able to mark each Tag.Name as unique simply.
Thanks.
This may work:
var place = new Place
{
Name = "The Old Blue Last",
URL = "old-blue-last-pub",
Address = "38 Great Eastern St",
City = "London",
PostCode = "EC2A 3ES",
Website = "www.theoldbluelast.com",
Phone = "123 456 789", // updated number
About = "Pub of Vice Magazine",
Image = "noimage.png",
TagID = db.Tags.Single(t => t.Name == "Bakery").TagID
};
db.Places.AddOrUpdate(p => p.Name, place);
db.SaveChanges();
Since "The Old Blue Last" is already there, and we've updated based on p.Name, it should only update that entry changing Phone to "123 456 789". This similar to what you have tried, but may work. See more here.
You also mentioned that you are not sure what p => p.Name does. The => is called a Lambda Expression. It is an anonymous function. It is a method without a declaration, access modifier, return type, name etc. It's a short hand expression that allows you to write a method in the place you are going to use it.
See more here and here..

CRM 2011 Create Product Plugin

I am trying to create a new product with a plugin, but I get this exception:
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
This is the code to create the product
EntityReference ugRef = new EntityReference(ug.LogicalName, ug.UoMScheduleId.Value);
EntityReference uRef = new EntityReference(u.LogicalName, u.UoMId.Value);
Product product = new Product()
{
Name = pName,
ProductNumber = pNumber,
QuantityDecimal = 2,
DefaultUoMScheduleId = ugRef,
DefaultUoMId = uRef
};
service.Create(product);
All variables have been tested, they all have values. The unit is correct for the unit group - if I change either I get an exception saying as much.
The problem is definitely with this piece of the code as there is a lovely lead with the expected 1st and last name when the code is altered to this:
EntityReference ugRef = new EntityReference(ug.LogicalName, ug.UoMScheduleId.Value);
EntityReference uRef = new EntityReference(u.LogicalName, u.UoMId.Value);
Lead l = new Lead();
l.FirstName = uRef.Id.ToString();
l.LastName = uRef.LogicalName;
service.Create(l);
/*
Product product = new Product()
{
Name = (String)staged.Attributes["wishlist_name"],
ProductNumber = (String)staged.Attributes["wishlist_barcode"],
QuantityDecimal = 2,
DefaultUoMScheduleId = ugRef,
DefaultUoMId = uRef
};
service.Create(product);
*/
pName and pNumber are strings.
u and ug are a Unit and a Unit Group.
I changed the code to:
query = new QueryByAttribute("uom");
query.ColumnSet = new ColumnSet("name", "uomscheduleid");
query.Attributes.AddRange("name");
query.Values.AddRange("1");
UoM unit = (UoM)service.RetrieveMultiple(query).Entities[0];
Product newProduct = new Product
{
ProductNumber = "1t2y3u",
Name = "Example Banana Product",
QuantityDecimal = 1,
DefaultUoMScheduleId = unit.UoMScheduleId,
DefaultUoMId = unit.ToEntityReference()
};
service.Create(newProduct);
The same error is thrown.
I am about to strip my moer with this.
Couple things to look at.
It looks like your tried to simplify your code in the first example, but may have removed the source of your bug, but luckily, you added it to your last example :) I'm guessing staged does not contain "wishlist_name", and therefor is giving you the error you see. You should always use the typed GetAttributeValue method defined in the Entity class: staged.GetAttributeValue<String>("wishlist_name"). It will perform a null check and return the default for the type.
Check all of your other plugins, to see if another plugin is fired upon the creation of the Product, that is possibly doing some extra logic if the DefaultUoMScheduleId or DefaultUoMId is populated. Your create in this plugin could be getting an error from another "nested" plugin.
Instead of creating temporary Entity Reference variables, use the ToEntityReference() method defined in the entity class, it makes the code look a little cleaner IMHO.
Product product = new Product()
{
Name = (String)staged.Attributes["wishlist_name"],
ProductNumber = (String)staged.Attributes["wishlist_barcode"],
QuantityDecimal = 2,
DefaultUoMScheduleId = ug.ToEntityReference(),
DefaultUoMId = u.ToEntityReference()
};

Categories