How do you save "Value" and "DataServiceCollection" objects that are part of another SharePoint list item? These are the only properties in my model that are not getting saved.
The generated Food SharePoint model has these sort of properties:
public class Food
{
DataServiceCollection<FoodIngredientValue> Ingredient;
FoodStateValue State;
string _StateValue
}
First, I don't know why there are two ways to add a state value in the model generated by SharePoint. I try populating either one and the state value doesn't populate in SharePoint.
Secondly, I tried populating the Ingredient collection through hard coding FoodIngredientValue objects to the food model before saving and also by querying SharePoint and assigning them to the Ingredient property but it doesn't get saved in SharePoint.
I add a new food item to the SharePoint list using the code below and I verified all three properties are populated in my model but none of them get saved.
public bool Insert(Food food)
{
var dataContext = new FoodDataContext(new Uri(EndpointUrl)) { Credentials = CredentialCache.DefaultNetworkCredentials };
dataContext.AddToFoods(food);
var response = dataContext.SaveChanges().FirstOrDefault();
return response.StatusCode == 201;
}
This was a great blog post explaining how to link complex list items (DataServiceCollecton and Value objects) in the SharePoint oData API:
http://blog.heeresonline.com/2014/07/sharepoint-wcf-dataservices-choice-lookup-column-editing/
The important thing to remember is to add the new item to the data context before you begin populating complex fields of type DataServiceCollection or Value objects. In the case of properties of type DataServiceCollection, there is a little more work that needs to be done to link them properly so they are saved in the data context as shown below for Ingredient. Here is an example of the code that finally worked:
var foodItem = new FoodItem();
dataContext.AddToFoods(foodItem); // Add to context before populating fields so the values are tracked.
foodItem = Mapper.Map(newFood, foodItem);
// DataValue Properties like StateValue objects can now be added since it is tracked by the context.
var state = StateValue.CreateStateValue("Montana");
foodItem.StateValue = state;
// Need to link special DataServiceCollection lists like Ingredient using a reference.
if (newFood.Ingredient != null)
{
newFood.Ingredient.ForEach(c =>
{
var ingredient = FoodIngredient.CreateFoodIngredientValue(c);
dataContext.AttachTo("FoodIngredientValue", ingredient);
foodItem.FoodIngredient.Add(ingredient);
dataContext.AddLink(foodItem, "FoodIngredient", ingredient);
});
}
Related
I am trying to add records from table position for positionName(s) to let user select a position for employee when editing.My last attempts is to add a navigation property like field in company model
public virtual ICollection<Position> Mpositions { get; set; }
But all I got so far is null ref exception or no element in viewModel with property "PositionName" ass per viewbag didn't bother using everybody keeps recommending to avoid it so not going to do so either.
public ActionResult Edit([Bind(Include = "CompanyID,CompanyName,EntityForm,Address,Dissolute,CreationDate,FiscaleYear,Description")] Company company)
{
var GlbUpdate = db.Companies.Include(c => c.Members).Include(p => p.Mpositions);
List<Company> mdlCompanies = new List<Company>();
foreach (var item in GlbUpdate)
{
if ((item.Mpositions==null) || (item.Mpositions.Count() == 0))
{
item.Mpositions = (ICollection<Position>)new SelectList(db.Positions.Except((IQueryable<Position>)db.Positions.Select(xk => xk.Members)), "PositionID", "PositionName");
}
mdlCompanies.Add(item);
//I tried first to edit the Mpositions property directly in gblUpdate
//item.Mpositions = (IEnumerable<Position>)db.Positions.Select(p => new SelectListItem { Value = p.PositionID.ToString(), Text = p.PositionName}) ;
//(ICollection<Position>)db.Positions.ToListAsync();
}
In the view I have this
List<SelectListItem> mPositionNames = new List<SelectListItem>();
#*#this yields no results if I try gettign it from the compani record itself it gives a logic error where all id match all positionNames impossible to select an item and only positions already registered are available on the dropDownlist*#
#{foreach (var item in Model.Mpositions)
{
mPositionNames.Add(new SelectListItem() { Text = item.PositionName, Value = item.PositionID.ToString(), Selected = (false) ? true : false });
#*#selected attribute set to false not an issue, no data to select from :p so far*#
}
}
#*#null exception(if i try to midify Mpositions directly in controler) here or empty list if modify it then put it with original query in a new list*#
<div class="SectionContainer R-sectionContainerData" id="MwrapperDataRight">
#Html.DropDownListFor(mpos => item.PositionID, (SelectList)Model.Mpositions)
</div>
All I want to do is pull the positions table to create a drop downList so users can change the position of an employee but since position has a 1>many relation with employee not companies it is not bound automatically by EF nor I seem to be able to use Include() to add it.
Your query for editing positions are complex. This query must edit person's info only. Using Edit action for formalizing position's edit are not correct.It's againts to Single Responsibility Principle. Use ViewComponents for this situation. Load positions separately from person info.
I found a suitable solution using a model that encapsulate the other entities then using Partialviews/RenderAction so each part handles one entity/operation.
Today I've faced one very strange behavior. After creating an object with Linq query and object initializer with setting property of List<string> type the original collection and the collection that the object contains have different entries order.
public class PrintHeaderModel
{
public List<string> Ships { get; set; }
}
...
var shipsList = new List<string>() { /* some items */ };
var model = (from inv in db.invoices
where inv.ListID == id && inv.RealmID == realmId
select new PrintHeaderModel()
{
Ships = shipsList,
}).FirstOrDefault();
After that the orders of entries in model.Ships and shipsList are different
Notes:
db is DbContext instance (I'm using Entity Framework and MySQL database)
shipsList is not sorted after it's filled
If I create model object without Linq (just with "new"), the order of entries is the same in model and in the list
The order becames correct if I reassign model.Ships right after model is created:
model.Ships = shipsList; // after that the order of entries is correct
The order of entries in model.Ships is not the same always. It changes randomly without any changes in code or database
Where was I wrong?
I have a two questions.
The first one is about that moment when you go to EDM and update your models from database and it rewrites the old models, losing everything you edited inside them. I read a little about this and it is said that you can create another models and make them also partial and there you may put again the fields so at the next update it won't affect your last changes. How can I do this? I have a separate project for my DAL and the models were generated from database (I have an EDM).
The second question is... But better I give an example. I have a model called Categories and another one CategoriesTranslations, both of them mapped from my database. Let's say you want to have a list of this categories inside a DropDownList() in many views of your website (of your different controllers). The DropDrown will have the value containing the translation which depends on the current language and the keys containing the category ID.
Here is an example of my list:
List<SelectListItem> listItems = new List<SelectListItem>();
var CategoriesTexts = db.Categories.Include(i => i.CategoryTexts).ToList();
foreach (var cat in CategoriesTexts)
{
var texts = cat.CategoryTexts.Where(w=>w.Language.Format == (string)Session["chosen_language"]).FirstOrDefault();
listItems.Add(new SelectListItem
{
Text = texts == null ? cat.Id.ToString() : texts.Name,
Value = cat.Id.ToString(),
});
}
Where should I put this code in my website structure (or how can I structure it) to make use of it in most of my Views?
Thank you!
For your first question
There is no need to make partial classes just to fix the naming when you update EF EDMX file. Actually you shouldn't delete the model class from the Edmx when you make update to your database all you need to do is to update the model and it will save your navigation properties names as you made them already.
For your second Question
Although I don't agree with you about what you're doing to get the categories to the DropDownList, But you could make this as Extension method for the IEnumerable<Category> and put this method in ViewModelExtensions project
e.g.
public static IList<SelectListItem> ToDropDownList(this IEnumerable<Category> query)
{
List<SelectListItem> listItems = new List<SelectListItem>();
foreach (var cat in query)
{
var texts = cat.CategoryTexts.Where(w=>w.Language.Format == (string)Session["chosen_language"]).FirstOrDefault();
listItems.Add(new SelectListItem
{
Text = texts == null ? cat.Id.ToString() : texts.Name,
Value = cat.Id.ToString(),
});
}
}
then just call it in your controllers like this:
var list = db.Categories.Include(i => i.CategoryTexts).ToDropDownList();
ASP.NET C# MVC 4 Code First application - in Visual Studio 2012 Express, SQL Server 2012 Express.
I have a places object. I would like to output the name of all places in a list - with a check box next to each.
I would then like logged in users to select the places they like - and have that saved. Then later they can login and see a them all again, with the appropriate check boxes selected.
What is the best approach? I'm new to MVC and not sure of best practice here.
thanks
Update
The below CheckboxListFor helper worked great, though it wasn't obvious how to process the user selection (it just returns a list of IDs).
I created the below to take that list of IDs - convert it to a list of objects, and add it to the SelecteCities list in the view model. This will select all the checkboxes that the user selected before the page was posted:
public ActionResult Examples(PostedCities postedCities)
{
// ViewModel
CitiesViewModel cvm = new CitiesViewModel();
// Create list of cities
List<City> cities = new List<City>{
new City { Id = 1, Name = "London"},
new City { Id = 2, Name = "Saigon"},
new City { Id = 3, Name = "New York"}
};
// Assign list of cities to ViewModel
cvm.AvailableCities = cities;
// If posted cities present, user posted something (else probably first call)
if (postedCities.CityIDs != null)
{
// temporary city object
City cty = new City();
// List of selected cities
List<City> selCities = new List<City>();
// Go through each postedCity ID
foreach (string s in postedCities.CityIDs)
{
// Get ID of postedCity
int IdSel = Convert.ToInt32(s);
// Lookup city Id in cities
cty = cities.Single(c => c.Id == IdSel);
// Add selected city to cty object
selCities.Add(cty);
}
// Fill cvm.SelectedCities with selCities
cvm.SelectedCities = selCities;
}
return View(cvm);
}
This works - is it a good approach or have I overcomplicated it? Or done something badly?
You can save yourself the work and use the existing MvcCheckBoxList library.
Install it with nuget using the command:
PM> Install-Package MvcCheckBoxList
Here is their home page: MvcCheckBoxList
And here is the documentation: MvcCheckBoxList/Documentation
Other solutions will require some ugly coding.
Update
As Klas Mellbourn suggested (I'm sorry for taking it for granted) a view model with a list will be the best practice for such sceneria. The documentation link I provided contains such examples for you to understand more easily.
I would say that MVC best practices would be to have a viewmodel mirroring the fields you wish to display. It would contain a List with items, each item containing a placename string and a bool for the checkbox.
In the controller method that displays the page you build the view model based on the places objects that you have populated from the database using Entity Framework.
The users presumably save the state using some command, a submit button perhaps. This calls a second controller method that reads the viewmodel and persists the content using Entity Framework.
I've been having a problem for some time, and I've exhausted all means of figuring this out for myself.
I have 2 lists in a MS Sharepoint 2010 environment that are holding personal physician data for a medical group...nothing special just mainly text fields and a few lookup choice fields.
I am trying to write a program that will migrate the data over from List A to List B. I am using LINQ to Sharepoint to accomplish this. Everything compiles just fine, but when it runs and hits the SubmitChanges() method, I get a runtime error that states:
"All new entities within an object graph must be added/attached before changes are submitted."
this issue must be outside of my realm of C# knowledge because I simply cannot find the solution for it. The problem is DEFINITELY stemming from the fact that some of the columns are of type "Lookup", because when I create a new "Physician" entity in my LINQ query, if I comment out the fields that deal with the lookup columns, everything runs perfectly.
With the lookup columns included, if I debug and hit breakpoints before the SubmitChanges() method, I can look at the new "Physician" entities created from the old list and the fields, including data from the lookup columns, looks good, the data is in there the way I want it to be, it just flakes out whenever it tries to actually update the new list with the new entities.
I have tried several methods of working around this error, all to no avail. In particular, I have tried created a brand new EntityList list and calling the Attach() method after each new "Physician" Entity is created, but to no avail, it just sends me around in a bunch of circles, chasing other errors such as "ID cannot be null", "Cannot insert entities that have been deleted" etc.,
I am no farther now than when I first got this error and any help that anyone can offer would certainly be appreciated.
Here is my code:
using (ProviderDataContext ctx = new ProviderDataContext("http://dev"))
{
SPSite sitecollection = new SPSite("http://dev");
SPWeb web = sitecollection.OpenWeb();
SPList theOldList = web.Lists.TryGetList("OldList_Physicians");
//Create new Physician entities.
foreach(SPListItem l in theOldList.Items)
{
PhysiciansItem p = new PhysiciansItem()
{
FirstName = (String)l["First Name"],
Title = (String)l["Last Name"],
MiddleInitial = (String)l["Middle Init"],
ProviderNumber = Convert.ToInt32(l["Provider No"]),
Gender = ConvertGender(l),
UndergraduateSchool =(String)l["UG_School"],
MedicalSchool = (String)l["Med_School"],
Residency = (String)l["Residency"],
Fellowship = (String)l["Fellowship"],
Internship = (String)l["Internship"],
PhysicianType = ConvertToPhysiciantype(l),
Specialty = ConvertSpecialties(l),
InsurancesAccepted = ConvertInsurance(l),
};
ctx.Physicians.InsertOnSubmit(p);
}
ctx.SubmitChanges(); //this is where it flakes out
}
}
//Theses are conversion functions that I wrote to convert the data from the old list to the new lookup columns.
private Gender ConvertGender(SPListItem l)
{
Gender g = new Gender();
if ((String)l["Sex"] == "M")
{
g = Gender.M;
}
else g = Gender.F;
return g;
}
//Process and convert the 'Physician Type', namely the distinction between MD (Medical Doctor) and
//DO (Doctor of Osteopathic Medicine). State Regualtions require this information to be attached
//to a physician's profile.
private ProviderTypesItem ConvertToPhysiciantype(SPListItem l)
{
ProviderTypesItem p = new ProviderTypesItem();
p.Title = (String)l["Provider_Title:Title"];
p.Intials = (String)l["Provider_Title"];
return p;
}
//Process and convert current Specialty and SubSpecialty data into the single multi-choice lookup column
private EntitySet<Item> ConvertSpecialties(SPListItem l)
{
EntitySet<Item> theEntityList = new EntitySet<Item>();
Item i = new Item();
i.Title = (String)l["Provider Specialty"];
theEntityList.Add(i);
if ((String)l["Provider SubSpecialty"] != null)
{
Item theSubSpecialty = new Item();
theSubSpecialty.Title = (String)l["Provider SubSpecialty"];
theEntityList.Add(theSubSpecialty);
}
return theEntityList;
}
//Process and add insurance accepted.
//Note this is a conversion from 3 boolean columns in the SP Environment to a multi-select enabled checkbox
//list.
private EntitySet<Item> ConvertInsurance(SPListItem l)
{
EntitySet<Item> theEntityList = new EntitySet<Item>();
if ((bool)l["TennCare"] == true)
{
Item TenncareItem = new Item();
TenncareItem.Title = "TennCare";
theEntityList.Add(TenncareItem);
}
if ((bool)l["Medicare"] == true)
{
Item MedicareItem = new Item();
MedicareItem.Title = "Medicare";
theEntityList.Add(MedicareItem);
}
if ((bool)l["Commercial"] == true)
{
Item CommercialItem = new Item();
CommercialItem.Title = "Commercial";
theEntityList.Add(CommercialItem);
}
return theEntityList;
}
}
So this may not be the answer you're looking for, but it's what's worked for me in the past. I've found that updating lookup fields using Linq to Sharepoint to be quite frustrating. It frequently doesn't work, or doesn't work efficiently (forcing me to query an item by ID just to set the lookup value).
You can set up the entity so that it has an int property for the lookup id (for each lookup field) and a string property for the lookup value. If, when you generate the entities using SPMetal, you don't generate the list that is being looked up then it will do this on it's own. What I like to do is (using your entity as an example)
Generate the entity for just that one list (Physicians) in some temporary folder
Pull out the properties for lookup id & value (there will also be private backing fields that need to come along for the ride too) for each of the lookups (or the ones that I'm interested in)
Create a partial class file for Physicians in my actual project file, so that regenerating the entire SPMetal file normally (without restricting to just that list) doesn't overwrite changes
Paste the lookup id & value properties in this partial Physicians class.
Now you will have 3 properties for each lookup field. For example, for PhysicianType there will be:
PhysicianType, which is the one that is currently there. This is great when querying data, as you can perform joins and such very easily.
PhysicianTypeId which can be occasionally useful for queries if you only need ID as it makes it a bit simpler, but mostly I use it whenever setting the value. To set a lookup field you only need to set the ID. This is easy, and has a good track record of actually working (correctly) in my experiences.
PhysicianTypeValue which could be useful when performing queries if you just need the lookup value, as a string (meaning it will be the raw value, rather than something which is already parsed if it's a multivalued field, or a user field, etc. Sometimes I'd rather parse it myself, or maybe just see what the underlying value is when doing development. Even if you don't use it and use the first property, I often bring it along for the ride since I'm already doing most of the work to bring the PhysicianTypeId field over.
It seems a bit hacky, and contrary to the general design of linq-to-SharePoint. I agree, but it also has the advantage of actually working, and not actually being all that hard (once you get the rhythm of it down and learn what exactly needs to be copied over to move the properties from one file to another).