EntityRef<T> Issues, not returning value from Lookup List - linq

Ok, I'll explain this as much as I can...
I've got a Site Lookup Column called EEE Content Type which refers to the Site Content Item Type Types List.
Now in my custom list (which inherits from Item), I am referencing that column, and it comes up in sharepoint fine and displays the lookup values.
The issue is when I'm using SPMetal.exe to generate the types it whinges about "Key isn't present in the dictionary" and fails. So I remove the definition of the column in the parameters.xml file for SPMetal, and re-generate the classes.
Now I've manually added the property and association.
private EntityRef<SiteContentItemTypeItem> _eeeContentType;
[Association(Name = "EEE_x0020_Content_x0020_Type", Storage = "_eeeContentType", MultivalueType = AssociationType.Single, List = "Site Content Item Types")]
public SiteContentItemTypeItem EEEContentType
{
get
{
return this._eeeContentType.GetEntity();
}
set
{
this._eeeContentType.SetEntity(value);
}
}
SiteContentItemTypeItem inherits from Item so its class is empty.
But when I load the custom list I have created, i get the first entry and the EEEContentType field is null...
using (IntranetDataContext context = new IntranetDataContext("http://siteurl")) {
context.ObjectTrackingEnabled = false;
EntityList<SiteContentItem> alerts = context.GetList<SiteContentItem>("User Alerts");
SiteContentItem alert = (from tmpalert in alerts where tmpalert.Id == 1 select tmpalert).First();
SiteContentItemTypeItem contentType = alert.EEEContentType;
}
I'm all out of ideas...
Should the List value in the Association attribute be that of a collection in the class or is it refering to the actual lookup list name?

Figured it out...
Stupid of me to "assume" when creating site lookup columns via code that SharePoint would use the proper naming conventions for FieldNames with spaces.
So the fieldName was correct, its InternalName wasn't the one I was expecting. And as sharepoint linq requires the internal names, it was throwing internal exceptions in the Linq.SharePoint DLL.

Related

LINQ query left joining two tables with concatenation

I am using this as a reference -- how concatenate multiple rows in LINQ with two tables?
I have the exact same needs, except that not all "printers" have "resolutions". In my particular case, I have a Lead table, which stores some basic information. Then there is a tag table, which stores tags used for the Lead. Not every lead has a tag.
This is what I have so far based on the above reference:
var leads = _dbRO.Leads.Join(_dbRO.Tags, p => p.LeadId, r => r.EntityId, (p, r) => new
{
LeadId = p.LeadId,
GigDate = p.GigDate,
Location = p.Location,
Tags = String.Join("|", _dbRO.Tags.Where(k => k.EntityId == p.LeadId)
.Select(lm => lm.TagName.ToString()))
}).Distinct();
This works well for me. However, leads without tags are NOT returned. How do I ensure all leads are returned regardless of tags. An empty string or null for Tags field would be fine.
Also if you don't mind, if I want to return the Tags in an object array, how do I do that? The reason is because there could be additional information associated with each tag, like color etc. So a simple concatenated string might not be sufficient.
Thanks a bunch!
I've figured out -- I do not need to join the tag table at all. This causes the problem. I just need to select from my Lead table and in the Select section, get the tags as I was already doing.
If you’ve declared a relationship between Lead and Tag entity types, then EF already supplies your requirements through the Include() extension method.
ctx.Leads.Include(l => l.Tags).ToList()
This requires that Lead declares a navigation property to Tag as shown below.
class Lead
{ ... public List<Tag> Tags { get; set; } }

Cannot specify child attributes in the columnset for Retrieve

In attempting to merge contacts in Microsoft CRM, I am using the following code -
//c1ID and c2ID are GUIDs of duplicated contacts.
EntityReference target = new EntityReference();
target.LogicalName = Contact.EntityLogicalName;
target.Id = c2ID;
MergeRequest merge = new MergeRequest();
// SubordinateId is the GUID of the account merging.
merge.SubordinateId = c1ID;
merge.Target = target;
merge.PerformParentingChecks = true;
Contact updater = new Contact();
Contact updater2 = new Contact();
updater = (Contact)xrmSvc.ContactSet.Where(c => c.ContactId.Equals(c1ID)).First();
updater2 = (Contact)xrmSvc.ContactSet.Where(c => c.ContactId.Equals(c2ID)).First();
MergeResponse mergedR = (MergeResponse)xrmSvc.Execute(merge);
When I try my Execute call here,I get this error -
Cannot specify child attributes in the columnset for Retrieve. Attribute: owneridname.
Am I not setting something correctly?
Having updatecontent does not change the issue. In fact, I get the error on lookups entered into the updatecontent. I find you have to build new entityreferences:
if (match.Contains("new_mostrecentcampaign"))
master["new_mostrecentcampaign"] =
new EntityReference(match.GetAttributeValue<EntityReference>("new_mostrecentcampaign").LogicalName
, match.GetAttributeValue<EntityReference>("new_mostrecentcampaign").Id);
...
Merge.UpdateContent = master
...
I realize this is a pretty old question, but for those of you who have run into the same issue in 2021 and beyond, here's the reason this error happens.
TL;DR: Ensure the EntityReference values for the attributes does not specify the Name property.
Explanation:
Everything that gets added to the Entity set to UpdateContent will be applied to the Target contact. When programmatically executing a MergeRequest within a plugin/workflow, the attributes of the UpdateContent get applied (as desired).
Where this breaks down is for EntityReference value types (lookups). The internal Microsoft code that performs this operation tries to interpret all properties of the EntityReference object, including Name.
So when the existing values from the SubordinateId contact are pulled using IOrganizationService.Retrieve (to dynamically get the latest version), the Name property is automatically set for those lookup attributes (the child record). This operation is not valid, even though it's not the user code that's directly executing it.
This brings us full circle to explain the original error:
Cannot specify child attributes in the columnset for Retrieve
I wish I had some documentation for this, but although the official documentation notes that the UpdateContent is optional, experience proves that it is in fact necessary. In the MergeRequests I've tested, I always include that property in the request, and there's a post in the MSDN forums for Dynamics 3.0 that suggests the same.
In fact, when I try to merge two contacts in my org without UpdateContent assigned, I actually get a FaultException saying the following:
Required field 'UpdateContent' is missing
Even though the documentation says it's optional!
So I'd suggest populating the UpdateContent property with something as in the below and see if that works:
var merge = new MergeRequest
{
// SubordinateId is the GUID of the account merging.
SubordinateId = c1ID,
Target = target,
PerformParentingChecks = true,
UpdateContent = new Contact()
};

How do I return strong type object in Linq?

I have a stored proc that returns a list of users (rows in User table).
var admins = db.aspnet_UsersInRoles_GetUsersInRoles('/', "Admin");
LINQ generated aspnet_User classes for me, so can I somehow map the result to a List of aspnet_User type? Something like:
List<aspnet_User> admins = db.aspnet_UsersInRoles_GetUsersInRoles('/', "Admin");
Here is a capture of what is returned.
It's entirely possible that you just need:
List<aspnet_User> admins = db.aspnet_UsersInRoles_GetUsersInRoles('/', "Admin")
.ToList();
But it's hard to know without seeing what type the method call returns.
Perhaps this should be a comment but it is way too long...
Well, you do not really want the internal class <aspnet_User> you should want a MembershipUser.
So how about not using the stored procedure that comes with the membership provider but really use the Membership provider itsself.
There is a beautiful class: Roles in System.Web.Security
And it gives you this:
public static string[] GetUsersInRole(string roleName)
From here, a foreach to get the MembershipUser(s) in a list is not that complicated.
By default a stored procedure will return a type that it determines based on the output columns with Result tacked on to the end. It doesn't associate it with types you have already determined. To change this, you can either change the Return Type in the property window to the type you have already defined in your model, or when dragging the stored proc into your model, drop it directly on the type that you want the stored proc to be mapped into.
You don't get the opportunity to change the column mappings for stored procs however, so make sure the shape that the stored proc generates is the same as your target object structures.
It's an old post and I was working on it today and I get the same issue,
I think you are requesting asp membership ?
You can not convert this stored procedure to aspnet_User because it returns aspnet_UsersInRoles_GetUsersInRolesResult type.
but from this aspnet_UsersInRoles_GetUsersInRolesResult you can get userName, then request the aspnet_User table:
String app = "your application name";
String role = "your role name";
ArrayList userInRoleList = new ArrayList();
//Get the role ID
ASPNETDBDataContext aspDB = new ASPNETDBDataContext();
var userInRole = aspDB.aspnet_UsersInRoles_GetUsersInRoles(app, role);
foreach (aspnet_UsersInRoles_GetUsersInRolesResult users in userInRole)
{
userInRoleList.Add(users.UserName);
}

Error when I try to read/update the .Body of a Task via EWS Managed API - "You must load or assign this property before you can read its value."

I am using the Exchange Web Services Managed API to work with Tasks (Exchange 2007 SP1). I can create them fine. However, when I try to do updates, it works for all of the fields except for the .Body field. Whenever I try to access (read/update) that field, it gives the following error:
"You must load or assign this property before you can read its value."
The code I am using looks like this:
//impersonate the person whose tasks you want to read
Me.Impersonate(userName); //home-made function to handle impersonation
//build the search filter
Exchange.SearchFilter.SearchFilterCollection filter = New Exchange.SearchFilter.SearchFilterCollection();
filter.Add(New Exchange.SearchFilter.IsEqualTo(Exchange.TaskSchema.Categories, "Sales"));
//do the search
EWS.Task exTask = esb.FindItems(Exchange.WellKnownFolderName.Tasks, filter, New Exchange.ItemView(Integer.MaxValue));
exTask.Subject = txtSubject.Text; //this works fine
exTask.Body = txtBody.Text; //This one gives the error implying that the object isn't loaded
The strange thing is that, inspecting the property bag shows that the object contains 33 properties, but {Body} is not one of them. That property seems to be inherited from the base class .Item, or something.
So, do I need to re-load the object as type Item? Or reload it via .Bind or something? Keep in mind that I need to do this with thousands of items, so efficiency does matter to me.
Calling the Load method solved my problem :)
foreach (Item item in findResults.Items)
{
item.Load();
string subject = item.Subject;
string mailMessage = item.Body;
}
I had the same problem when using the EWS. My Code is requesting the events(Appointments) from the
Outlook calendar, at the end I couldn't reach to the body of the Event itself.
The missing point in my situation was the following "forgive me if there is any typo errors":
After gathering the Appointments, which are also derived from EWS Item Class, I did the following:
1- Create a List with the type Item:
List<Item> items = new List<Item>();
2- Added all appointments to items list:
if(oAppointmentList.Items.Count > 0) // Prevent the exception
{
foreach( Appointment app in oAppointmentList)
{
items.Add(app);
}
}
3- Used the exchanged service "I have already created and used":
oExchangeService.LoadPropertiesForItems(items, PropertySet.FirstClassProperties);
now if you try to use app.Body.Text, it will return it successfully.
Enjoy Coding and Best Luck
I forgot to mention the resource:
http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/ce1e0527-e2db-490d-817e-83f586fb1b44
He mentioned the use of Linq to save the intermediate step, it will help you avoid using the List items and save some memory!
RockmanX
You can load properties using a custom property set. Some properties are Extended properties instead of FirstClassProperties.
Little example:
_customPropertySet = new PropertySet(BasePropertySet.FirstClassProperties, AppointmentSchema.MyResponseType, AppointmentSchema.IsMeeting, AppointmentSchema.ICalUid);
_customPropertySet.RequestedBodyType = BodyType.Text;
appointment.Load(_customPropertySet);

best practice Treeview populating from differents kinds of objects

I would like to populate a Treeview.
Here is what I have in DB :
table : Box
BoxID
BoxName
table Book :
BookID
BookName
BoxID (fk Box.BoxID)
table Chapter:
ChapterID
ChapterName
BookID (fk Book.BookID)
As you may know a treeview is made up of treenode object.
A treenode object have a text property and a tag property.
The "text" property is the text that it's display on the screen for this node and the "tag" is an "hidden" value (usually uses to identify a node)
So in my case; the fields ending with ID will be used in the "tag" property and the fields ending with Name will be used in the "text" property
example :
so for a book; I will use the BookID field for the "tag" property and BookName field for the "text" property
note : I use a dbml so I have a Book object, Box object and Chapter object and I use linq to get them from the db.
So my question is; what is the best practice to build this tree?
I have a solution but it's really ugly because it looks like I'm duplicating the code.
The problem is that the values I need to extract for the text and tag properties are identified by differents fields name in the db
So for the book level, I need to get the BookID field to populate the tag property of my node; for the box level, I need to get the BoxID field to populate the tag property , ....
How can I make a kind of generic way to do it ?
I hope I made myself clear enough, don't hesitate to ask me questions :)
Thx in advance
Here is what I have for the moment
I get the list of box with a linq (dbml) request.
List<Box> MyListofBox = getMyListofBox();
Treenode tnBox = null;
Treenode tnBook =null;
foreach(Box b in MyListofBox )
{
tnBox = new TreeNode();
tnBox.tag = b.BoxID;
tnBox.text = b.BoxName;
List<Book> MyListofBook = getMyListofBookByBoxID(b.BoxID)
foreach(Book boo in MyListofBook )
{
tnBook = new TreeNode();
tnBook.tag = boo.BookID;
tnBook.text = boo.BookName;
tnBox.nodes.add(tnBook);
}
mytreeview.nodes.add(tnBox);
}
but of course I don't like this solution...
do you have a better way ?
I would extract the you need from the database in the form of a struct, possibly via the anonnoumous type that has been added to C# together with linq. Then I would populate insert this data into the place in the tree.
From what I get, you are trying to get each property separately, which will not work so well, because then you will have to make a call to the database for each separate property, which is very wasteful.
Addition based on what you have added
I do not believe the code can be more compact - the names you call are similar, but not the same and the way you do it was what I was trying to explain earlier.
You could
Define an key/value interface that both Box and Book implement
Define a delegate that returns a TreeNode and create delegate methods that accept Box and Book
However, I think the code is fine as written. Sometimes you just have to code it and there's little point in further abstracting or optimizing it.
The only issue I see in the code is that you're making a database call in a loop. Whether or not that's a problem depends on the application.

Resources