I am working in Ektron 9.0.
I have two different custom property associated with a taxonomy in Ektron.
Say, Taxonomy called "P",this has got two custom properties,
*P1
*P2
Each of these custom property has its own value.
(For eg:
*P1 - V1
*P2 -V2)
Now i am trying to pull all taxonomies in Ektron,based on the names and values of these custom properties.
i.e, get all taxonomies in Ektron which has got custom property name as P1 and corresponding value as V1 AND another custom property name as P2 and corresponding value as V2.
Code :
CriteriaFilterGroup<TaxonomyCustomProperty> criteriaFilterGrp1= new CriteriaFilterGroup<TaxonomyCustomProperty>();
criteriaFilterGrp1.AddFilter(TaxonomyCustomProperty.Name,
CriteriaFilterOperator.EqualTo,"P1");
criteriaFilterGrp1.AddFilter(TaxonomyCustomProperty.Value,
CriteriaFilterOperator.EqualTo, "V1");
criteriaFilterGrp1.Condition = LogicalOperation.And;
custCtriteria.FilterGroups.Add(criteriaFilterGrp1);
CriteriaFilterGroup<TaxonomyCustomProperty> criteriaFilterGrp2= new CriteriaFilterGroup<TaxonomyCustomProperty>();
criteriaFilterGrp2.AddFilter(TaxonomyCustomProperty.Name,
CriteriaFilterOperator.EqualTo, "P2";
criteriaFilterGrp2.AddFilter(TaxonomyCustomProperty.Value,
CriteriaFilterOperator.EqualTo, "V2");
custCtriteria.FilterGroups.Add(criteriaFilterGrp2);
Here,When I Add the Filter criteria by the two taxonomy names and their corresponding value as as follows,
I am not getting any results,as it is looking for a taxonomy custom property that satisfies the all four conditions that I have given.
How can i resolve this?
My guess is that the underlying code is behaving differently from how it might be expected to operate - instead of handling taxonomy items with custom properties, it is handling the properties themselves. This is consistent with the behavior of other ektron APIs in terms of its typing, but inconsistent in that it returns the associated taxonomy items themselves (though this is clearly the more desirable outcome). With respect to this design, it makes sense that you cannot retrieve a custom property that has name equal to p1 and p2.
The solution is to retrieve lists for each property you want to filter by independently, and then intersect these lists. Conveniently, ektron returns iQueryable lists, so you can do this trivially with linq:
CriteriaFilterGroup<TaxonomyCustomProperty> criteriaFilterGrp1= new CriteriaFilterGroup<TaxonomyCustomProperty>();
criteriaFilterGrp1.AddFilter(TaxonomyCustomProperty.Name,
CriteriaFilterOperator.EqualTo,"P1");
criteriaFilterGrp1.AddFilter(TaxonomyCustomProperty.Value,
CriteriaFilterOperator.EqualTo, "V1");
criteriaFilterGrp1.Condition = LogicalOperation.And;
custCtriteria.FilterGroups.Add(criteriaFilterGrp1);
var itemsWithProp1= taxManager.getList(custCtriteria);
custCtriteria = new criteria();
CriteriaFilterGroup<TaxonomyCustomProperty> criteriaFilterGrp2= new CriteriaFilterGroup<TaxonomyCustomProperty>();
criteriaFilterGrp2.AddFilter(TaxonomyCustomProperty.Name,
CriteriaFilterOperator.EqualTo, "P2";
criteriaFilterGrp2.AddFilter(TaxonomyCustomProperty.Value,
CriteriaFilterOperator.EqualTo, "V2");
custCtriteria.FilterGroups.Add(criteriaFilterGrp2);
var itemsWithProp2 = taxManager.getList(custCtriteria);
var itemsWithBoth = itemsWithProp1.Intersect(itemsWithProp2);
While this is not the most elegant or efficient solution, I'm not sure that there is a better way within Ektron's API, outside of crafting a custom SQL query.
Related
I'm using early-bound entities, generated by CrmSvcUtil, and I'm testing the SDK by retrieving an account entity:-
var account = myContext.AccountSet.FirstOrDefault(o => o.Id == Guid.Parse("..."));
(BTW is there an easier way to retrieve an entity by ID?!)
Looking at the account object that is returned, I can see various properties of type OptionSetValue (e.g. "PreferredContactMethodCode"). How do I get the actual item from this OptionSetValue object?
Similarly, there are numerous properties of type EntityReference, which contains an Id and LogicalName (the entity name I presume). How can I populate such a property - is it one of the Get... methods? And do these have to be called separately, or is it possible to "pre-fetch" certain relationships as part of the initial query that retrieves the account entity?
Similarly with the various IEnumerable<> properties (which presumably correspond to 1-M entity relationships), e.g. a property called "opportunity_customer_accounts" of type IEnumerable. How do I populate one of these properties? And (again) does this have to be done as a separate query/method call, or can it be "pre-fetched"?
Retrieve
I'm not really sure how much simpler the retrieve operation could get but for a single record the user of the context is probably overkill. So you could retrieve a specific record where you know directly with the IOrganizationService:
account = service.Retrieve("account", Guid.Parse("..."), new ColumnSet(true));
Option Set Labels
For the OptionSet labels you can look at my answer here: How to get the option set from a field in an entity in CRM 2011 using crm sdk and C#.
If you need the label for multiple OptionSet's on an entity you may want to just retrieve the Entity's metadata once (http://srinivasrajulapudi.blogspot.com/2012/01/retrieve-entity-metadata-in-crm-2011.html):
string entityName ="contact";
// Get the metadata for the currently list's entity
// This metadata is used to create a "Property Descriptor Collection"
RetrieveEntityRequest mdRequest = new RetrieveEntityRequest ( )
{ EntityFilters = EntityFilters.All,
LogicalName = entityName,
RetrieveAsIfPublished = false
};
// Execute the request
RetrieveEntityResponse entityResponse = ( RetrieveEntityResponse ) this.ServiceProxy.Execute ( mdRequest );
EntityMetadata entityData = entityResponse.EntityMetadata;
//To Get Option Set Data
var preferdList= ( entityData.Attributes.Where ( p => p.LogicalName == "preferredcontactmethodcode" ) ).ToList ( ).FirstOrDefault ( ); ;
if ( preferdList != null ) {
PicklistAttributeMetadata optionList= preferdList as PicklistAttributeMetadata;
OptionSetMetadata opValues= optionList.OptionSet;
foreach ( var op in opValues.Options ) {
preferedMethod.Add ( new OptionSet { Value = op.Value.Value, Text = op.Label.LocalizedLabels[0].Label.ToString() } );
}
}
EntityReference()
To set an EntityReference typed field:
account.primarycontact = new EntityReference("contact", Guide.Parse("..."));
If they have a value and you requested the column in your ColumnSet() they should be populated, so I'm not really sure I understand your question. If you mean, you want the full record then you need to do a service.Retrieve(...) for the record.
Related Entities (i.e., opportunity_customer_accounts)
This is where using an OrganizationServiceContext makes life easier (https://msdn.microsoft.com/en-us/library/gg695791.aspx):
context.LoadProperty(contact, "transactioncurrency_contact");
// read related entity dynamically
var currency = contact.GetRelatedEntity("transactioncurrency_contact");
Console.WriteLine(currency.GetAttributeValue("currencyname"));
// read related entity statically
var currencyStatic = contact.transactioncurrency_contact;
Console.WriteLine(currencyStatic.CurrencyName);
If you are not using an OrganizationServiceContext you can try using a QueryExpression using LinkedEntities, although I've never done this to populate an early-bound entity so I don't know if it works (perhaps someone will add a comment with the answer.)
I have a document in RavenDB that looks looks like:
{
"ItemId": 1,
"Title": "Villa
}
With the following metadata:
Raven-Clr-Type: MyNamespace.Item, MyNamespace
Raven-Entity-Name: Doelkaarten
So I serialized with a type MyNamespace.Item, but gave it my own Raven-Entity-Name, so it get its own collection.
In my code I define an index:
public class DoelkaartenIndex : AbstractIndexCreationTask<Item>
{
public DoelkaartenIndex()
{
// MetadataFor(doc)["Raven-Entity-Name"].ToString() == "Doelkaarten"
Map = items => from item in items
where MetadataFor(item)["Raven-Entity-Name"].ToString() == "Doelkaarten"
select new {Id = item.ItemId, Name = item.Title};
}
}
In the Index it is translated in the "Maps" field to:
docs.Items
.Where(item => item["#metadata"]["Raven-Entity-Name"].ToString() == "Doelkaarten")
.Select(item => new {Id = item.ItemId, Name = item.Title})
A query on the index never gives results.
If the Maps field is manually changed to the code below it works...
from doc in docs
where doc["#metadata"]["Raven-Entity-Name"] == "Doelkaarten"
select new { Id = doc.ItemId, Name=doc.Title };
How is it possible to define in code the index that gives the required result?
RavenDB used: RavenHQ, Build #961
UPDATE:
What I'm doing is the following: I want to use SharePoint as a CMS, and use RavenDB as a ready-only replication of the SharePoint list data. I created a tool to sync from SharePoint lists to RavenDB. I have a generic type Item that I create from a SharePoint list item and that I serialize into RavenDB. So all my docs are of type Item. But they come from different lists with different properties, so I want to be able to differentiate. You propose to differentiate on an additional property, this would perfectly work. But then I will see all list items from all lists in one big Items collection... What would you think to be the best approach to this problem? Or just live with it? I want to use the indexes to create projections from all data in an Item to the actual data that I need.
You can't easily change the name of a collection this way. The server-side will use the Raven-Entity-Name metadata, but the client side will determine the collection name via the conventions registered with the document store. The default convention being to use the type name of the entity.
You can provide your own custom convention by assigning a new function to DocumentStore.Conventions.FindTypeTagName - but it would probably be cumbersome to do that for every entity. You could create a custom attribute to apply to your entities and then write the function to look for and understand that attribute.
Really the simplest way is just to call your entity Doelkaarten instead of Item.
Regarding why the change in indexing works - it's not because of the switch in linq syntax. It's because you said from doc in docs instead of from doc in docs.Items. You probably could have done from doc in docs.Doelkaartens instead of using the where clause. They are equivalent. See this page in the docs for further examples.
how to display the some specific columns of table instead of whole table in entity framework.
using (DataEntities cxt = new DataEntities())
{
notes note = cxt.notes.Where(no => no.id == accID).SingleOrDefault();
return notes;
}
For this purpose, I would suggest you to make use of ViewModel like following :-
notes note = cxt.notes.SingleOrDefault(no => no.id == accID);
var model = new YourViewModel // Your viewModel class
{
ID = note.ID,
PropertyOne = note.PropertyOne, // your ViewModel Property
PropertyTwo = note.PropertyTwo
};
You can do this with QueryView.
This implies editing your model directly in XML as there is no designer support for this, but you will get an independant entity with less fields than the original one.
Advantages:
You can then query data base for this truncated entity directly (you will get only fields you need from the data base - no need to get whole entity from DB and trancate it in code)
It is good in scenarios where you want to send this truncated entity to the
client
with WCF to minimize traffic (e.g. when building big lists on client
that basically need only name and ID and no other entity specific
information).
Disadvantages:
This QueryView-based entity is read only. To make it writeable you will have to add r/w functionality yourself
I am trying to construct an SQL statement dynamically.
My context is created dynamically, using reflection finding classes deriving from EntityTypeConfiguration and adding them to DbModelBuilder.Configuration.
My EntityTypeConfiguration classes specify HasColumnName to map the Entity property name to db table column name, which I need to construct my SQL statement.
namespace MyDomain {
public class TestEntityConfig : EntityTypeConfiguration<TestEntity>{
Property("Name").HasColumnName("dbName");
}
}
From What I have researched, it seems I can get access to this information through MetadataWorkspace, which I can get to through ObjectContext.
I have managed to retrieve the the entity I am interested in with MetadataWorkspace.GetItem("MyDomain.TestEntity",DataSpace.OSpace), which gives me access to Properties, but none of the properties, of Properties, give me the name of the mapped db column, as specified with HasColumnName.
Also I am not clear what DataSpace.OSpace is and why my model is constructed in this space.
If Anyone can shed some light on this I would be grateful
UPDATE
Further to #Ladislav's comments. I discovered I can get the information as follows
For the class properties
ctx.MetadataWorkspace.GetItem<ClrEntityType>("MyDomain.TestEntity", DataSpace.OSpace)).Members
For the table properties
ctx.MetadataWorkspace.GetItem<EntityType>("CodeFirstDatabaseSchema.TestEntity",SSpace).Members
So given that I only know the type MyDomain.TestEntity and Memeber "Name". How would I go about to get "dbName". Can I always assume that my mapped class will be created in CodeFirstDatabaseSchema, om order to dynamically construct the identity to retrieve it from SSpace and how would I get to the correct Member in SSpace. Can I do something like
var memIndex = ctx.MetadataWorkspace.GetItem<ClrEntityType>("MyDomain.TestEntity", DataSpace.OSpace)).Members["Name"].Index;
var dbName = ctx.MetadataWorkspace.GetItem<EntityType>("CodeFirstDatabaseSchema.TestEntity",SSpace).Members[memIndex];
MetadataWorkspace contanis several containers specified by DataSpace. Interesting for you are:
CSpace - description of conceptual model (this should contain properties)
CSSpace - mapping of conceptual model to storage model (this should contain how classes / properties are mapped to tables / columns)
Suppose I have a class Customer that is mapped to the database and everything is a-ok.
Now suppose that I want to retrieve - in my application - the column name that NH knows Customer.FirstName maps to.
How would I do this?
You can access the database field name through NHibernate.Cfg.Configuration:
// cfg is NHibernate.Cfg.Configuration
// You will have to provide the complete namespace for Customer
var persistentClass = cfg.GetClassMapping(typeof(Customer));
var property = persistentClass.GetProperty("FirstName");
var columnIterator = property.ColumnIterator;
The ColumnIterator property returns IEnumerable<NHibernate.Mapping.ISelectable>. In almost all cases properties are mapped to a single column so the column name can be found using property.ColumnInterator.ElementAt(0).Text.
I'm not aware that that's doable.
I believe your best bet would be to use .xml files to do the mapping, package them together with the application and read the contents at runtime. I am not aware of an API which allows you to query hibernate annotations (pardon the Java lingo) at runtime, and that's what you would need.
Update:
Judging by Jamie's solution, NHibernate and Hibernate have different APIs, because the Hibernate org.hibernate.Hibernate class provides no way to access a "configuration" property.