Programmatically generated Lookup Field causes "System.ArgumentException: Value does not fall within the expected range" when creating new item
I created a content type TypeA that has a lookup field to basic ListB. Then I create a ListA that uses TypeA. Everything is created programmatically.
An exception is thrown when ListA's 'add new item' modal is supposed to load. It only happens when ListB has items in it. If ListB is empty, listA's 'add new item' modal loads and the lookup field to ListB correctly displays (None)
stack trace:
System.ArgumentException: Value does not fall within the expected range.
at Microsoft.SharePoint.SPFieldMap.GetColumnNumber(String strFieldName, Boolean bThrow)
at Microsoft.SharePoint.SPListItemCollection.GetColumnNumber开发者_Go百科(String groupName, Boolean bThrowException)
at Microsoft.SharePoint.SPListItemCollection.GetRawValue(String fieldname, Int32 iIndex, Boolean bThrow)
at Microsoft.SharePoint.SPListItem.GetValue(SPField fld, Int32 columnNumber, Boolean bRaw, Boolean bThrowException)
at Microsoft.SharePoint.SPListItem.GetValue(String strName, Boolean bThrowException)
at Microsoft.SharePoint.SPListItem.get_Item(String fieldName)
at Microsoft.SharePoint.WebControls.LookupField.get_DataSource()
at Microsoft.SharePoint.WebControls.LookupField.CreateChildControls()
at System.Web.UI.Control.EnsureChildControls()
at Microsoft.SharePoint.WebControls.BaseFieldControl.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Methods I use to create the content type, lists, and lookup field:
private SPContentType createContentType(SPSite site, string typeName, string groupName, string parentTypeName, string[] fields) {
try {
SPContentType testExist = site.RootWeb.ContentTypes[typeName];
if (testExist != null)
return testExist;
}
catch { }
SPContentType parentType = site.RootWeb.ContentTypes[parentTypeName];
SPContentType contentType = new SPContentType(parentType, site.RootWeb.ContentTypes, typeName);
contentType.Group = groupName;
foreach (string field in fields) {
contentType.FieldLinks.Add(new SPFieldLink(site.RootWeb.GetField(field)));
}
contentType.FieldLinks["Title"].Required = false;
contentType.FieldLinks["Title"].Hidden = true;
site.RootWeb.ContentTypes.Add(contentType);
contentType.Update();
return contentType;
}
public SPFieldLookup createLookupField(string fieldName, string groupName, Guid listGuid, string lookupField, bool allowMultipleValues, bool isRequired) {
if (site.RootWeb.Fields.ContainsField(fieldName))
return null;
string internalName = site.RootWeb.Fields.AddLookup(fieldName, listGuid, isRequired);
SPFieldLookup lookup = site.RootWeb.Fields.GetFieldByInternalName(internalName) as SPFieldLookup;
lookup.AllowMultipleValues = allowMultipleValues;
lookup.LookupField = lookupField;
lookup.Group = groupName;
lookup.Update();
return lookup;
}
public SPList createList(string listName, string description, SPContentType contentType) {
if (web.Lists.TryGetList(listName) != null)
web.Lists[listName].Delete();
Guid newListGuid = web.Lists.Add(listName, description, SPListTemplateType.GenericList);
SPList newList = web.Lists[newListGuid];
newList.OnQuickLaunch = true;
newList.Update();
newList.ContentTypesEnabled = true;
SPContentType newType = newList.ContentTypes.Add(contentType);
newList.Update();
newList.ContentTypes["Item"].Delete();
newList.Update();
newList.Fields["Title"].Required = false;
newList.Fields["Title"].Hidden = true;
newList.Fields["Title"].Update();
SPView view = newList.DefaultView;
foreach (SPField field in newType.Fields) {
view.ViewFields.Add(field);
}
view.ViewFields.Delete("Title");
view.ViewFields.Delete("LinkTitle");
view.ViewFields.Delete("ContentType");
view.Update();
return newList;
}
Example
SPContentType typeB = createContentType(site, "Type B", "My Group", "Item", new string[] {"Salary"});
SPList listB = createList("List B", "my list b", typeB);
SPFieldLookup lookupB = createLookupField("B", "My Group", listB.ID, "Salary", false, false);
SPContentType typeA = createContentType(site, "Type A", "My Group", "Item", new string[] {"Name", "B"});
SPList listA = createList("List A", "my list a", typeA);
The SPFieldLookup.LookupField
property requires the field's internal name.
Solution is to make the following change (in the example):
SPFieldLookup lookupB = createLookupField("B", "My Group", listB.ID, listB.Fields["Salary"].InternalName, false, false);
精彩评论