Hey all, I was able to do this via a SELECT CASE statement, however I'm always trying to improve my code writing and was wondering if there was a better approach. Here's the scenario:
Each document has x custom fields on it.
There's y number of documents
However there's only 21 distinct custom fields, but they can obviously have n different combinations of them depending on the form.
So here's what I did, I created an object called CustomFields like so:
Private Class CustomFields
Public agentaddress As String
Public agentattorney As String
Public agentcity As String
Public agentname As String
Public agentnumber As String
Public agentstate As String
Public agentzip As String
... more fields here ....
End Class`
Then I went ahead and assigned the values I get from the user to each of those fields like so:
Set All of Our Custom Fields Accordingly
Dim pcc As New CustomFields()
pcc.agentaddress = agent.address1
pcc.agentattorney = cplinfo.attorneyname
pcc.agentcity = agent.city
pcc.agentname = agent.agencyName
pcc.agentnumber = agent.agentNumber
pcc.agentstate = agent.state
pcc.agentzip = agent.zip ....other values set to fields etc.
Now the idea is based upon what combo of fields come back based upon the document, we need to assign the value which matches up with that custom field's value. So if the form only needed agentaddress and agentcity:
'Now Let's Loop Through the Custom Fields for This Document
For Each cf As vCustomField In cc
Dim customs As New tblCustomValue()
Select Case cf.fieldname
Case "agentaddress"
customs.customfieldid = cf.customfieldid
customs.icsid = cpl.icsID
customs.value = pcc.additionalinfo
Case "agentcity"
customs.customfieldid = cf.customfieldid
customs.icsid = cpl.icsID
customs.value = pcc.additionalinfo
End Select
_db.tblCustomValues.InsertOnSubmit(customs)
_db.SubmitChanges()
This works, however we may end up having 100's of fields in the future so there a way to somehow "EVAL" (yes I know that doesn't exist in vb.net) the cf.fieldname and find it's corresponding value in the CustomFields object?
Just trying to write more efficient code and looking for some brainstorming here. Hopefully my code and description makes sense. If it doesn't let me know and I'll go hit my head up against the wall and try writing it again.
If I am reading your question correctly, you are trying to avoid setting the value of fields, when the field isn't used. If so, I would recommend you just go ahead and set the field to nothing in that case.
Related
Unable to get it to return any results. Compiles fine and does not error when it is run, but the results are always empty.
I have got this working if I restrict it to something like DisplayName or given name. But would like it to work no matter if the user puts in forename or surname first and that the user is not restricted to adhering to the DisplayName format of "Surname, Forename"
Dim searchterm As String = RouteData.Values("Search")
Dim domain As New PrincipalContext(ContextType.Domain, "Domain")
Dim user As New CustomUserPrincipal(domain)
Dim search As New PrincipalSearcher()
Dim results As PrincipalSearchResult(Of Principal)
jss.MaxJsonLength = Integer.MaxValue
user.Anr = String.Format("*{0}*", searchterm)
search.QueryFilter = user
CType(search.GetUnderlyingSearcher, DirectoryServices.DirectorySearcher).SizeLimit = 25
results = search.FindAll()
<DirectoryObjectClass("user")>
<DirectoryRdnPrefix("CN")>
Public Class CustomUserPrincipal
Inherits UserPrincipal
Public Sub New(context As PrincipalContext)
MyBase.New(context)
End Sub
<DirectoryProperty("anr")>
Public Property Anr As String
Get
Return CStr(ExtensionGet("anr")(0))
End Get
Set(value As String)
ExtensionSet("anr", value)
End Set
End Property
End Class
I am expecting an object that I can enumerate through and pull out individual UserPrincipals to extract details. But I only get an empty object
I think this is your problem:
user.Anr = String.Format("*{0}*", searchterm)
Specifically, that you're putting asterisks around your search term. According to the documentation, it will expand a search term like (anr=Smith) to something like this:
(|(displayName=smith*)(givenName=smith*)(legacyExchangeDN=smith)(physicalDeliveryOfficeName=smith*)(proxyAddresses=smith*)(Name=smith*)(sAMAccountName=smith*)(sn=smith*))
Notice that it already does a "starts with" type search. Putting your own wildcards in there messes it up.
More specifically, it's the asterisk at the beginning. I tested this in our own AD environment. If I search for (anr=*Gabriel*) or (anr=*Gabriel), I get no results. If I search for (anr=Gabriel*) I get results, but it really has no effect on the results (the results are the same as if I had searched for (anr=Gabriel)).
The solution is to change that line to this:
user.Anr = searchterm
It is not exactly equivalent to the "contains" search you seem to want, but putting a wildcard at the beginning of any search really kills performance anyway. It can no longer use any indexes to complete the search, so it's forced to look at every user account in your domain.
I need to retrieve the last row one data field. id is the primary key of my table. I'm trying to retrieve my final row data using its id
public AddExpenses[] GetFinalExpense(int numberOfExpenses)
{
return Conn.Table<AddExpenses>()
.OrderByDescending(expenses => expenses.Id)
.Take(numberOfExpenses)
.ToArray();
}
In my view model I have
var finalexpense = database.GetFinalExpense(1);
this is my code. when I tried to use this final row data to retrieve single data
ExpenseLabel = "Your expense is"+finalexpense;
in here final expense it does not show properties of the table to call. I need my finalexpense property to call it does not work
Concatenating a string with an object uses the default implementation of ToString which will yield something like AddExpenses[] for you, if finalexpense has a value !=null, since it is an array.
First of all, you'll have to get the item in the array
var finalExpenses = database.GetFinalExpense(1);
var finalExpense = finalExpenses[0];
Furthermore you'll have to make sure that your object is formatted properly. You could implement your own ToString method in AddExpenses class, but the simplest way would be to use string interpolation
var formattedExpense = $"{finalExpense.Expense} ({finalExpense.Date}, {finalExpense.Category})";
ExpenseLabel = $"Your expense is {formattedExpense}";
How you build formattedExpense is up to you, take the proposed string as a starting point and adapt it to your needs.
I have a Pages smart search index which uses the Standard analyzer. When I examine the generated index in Luke I can see that integer fields have a specific format. For example, all pages created by global administrator have the documentcreatedbyuserid field set to 10000000053.
Reading the documentation I see that integer fields like this need to be searched using a particular syntax:
+DocumentCreatedByUserID;(int)53;Administrator
However, when I pass this string to the following code as the searchQuery variable I get no results.
// Get search results
var parameters = new SearchParameters()
{
AttachmentOrderBy = "",
AttachmentWhere = "",
CheckPermissions = false,
ClassNames = null,
CombineWithDefaultCulture = false,
CurrentCulture = this.Context.CultureCode,
DefaultCulture = CultureHelper.GetDefaultCultureCode(this.Context.SiteName),
DisplayResults = resultsPerPage,
NumberOfProcessedResults = 100,
Path = startPath,
SearchFor = searchQuery,
SearchInAttachments = false,
SearchIndexes = index,
SearchSort = sort,
StartingPosition = (page - 1) * resultsPerPage,
User = this.Context.User.UserInfo
};
ds = CMS.Search.SearchHelper.Search(parameters);
This same code works fine for text field search queries. Can anyone explain:
Is there anything obvious I'm doing wrong?
What is the purpose of the final part of the +DocumentCreatedByUserID;(int)53;Administrator query. Why should I need to pass a text value here?
The field I actually want to search is a custom page type field called newstypeid, which I can see is storing its value in the same way in the index (e.g. a value of 34 is stored as 10000000034).
In Luke if I query +newstypeid:10000000034 I get results. So maybe an easier solution is to find a way to translate an integer to this Lucene format? (i.e. 34 to 10000000034)
UPDATE WITH SOLUTION
Thanks to #richard-Šůstek for pointing me in the right direction. The following method will return a search clause in the required format:
protected string GetIntegerIdClause(string field, int id)
{
var condition = string.Format("{0}:(int){1}", field, id).ToLower();
return SearchSyntaxHelper.CombineSearchCondition(null, new SearchCondition(condition, SearchModeEnum.ExactPhrase, SearchOptionsEnum.NoneSearch));
}
I think you should use SearchValueConverter class from the namespace CMS.Search. This class has static methods to convert specific data type values (int,datetime,etc.) to it's string representation for search terms construction.
Can you try using something like this to transform the searchQuery?:
var condition = new SearchCondition(null, searchModeEnum, SearchOptionsEnum.FullSearch);
searchQuery = SearchSyntaxHelper.CombineSearchCondition(searchText, condition);
I noticed that Kentico is internally calling this method when passing the value from search text box to SearchParameters. I haven't had a chance to test this though. Maybe some other method in SearchSyntaxHelper would be useful too.
Following on from my earlier question about creating Address Books (many thanks Peter!), I have a small throw-away console application doing just that and working great - but in addition I'm trying to update the metadata of a Keyword with the Item Id of the created Address Book.
Slightly shortened snippet ...
StaticAddressBook ab = new StaticAddressBook();
ab.Title = title;
ab.Key = key;
ab.Save();
// id is a correct Keyword TCM ID
Keyword k = tdse.GetObject(id, EnumOpenMode.OpenModeEdit);
if (k != null)
{
k.MetadataFields["addressbookid"].value[0] = ab.Id.ItemId;
k.Save(true);
}
I keep getting the following error on Save():
XML validation error. Reason: The element 'Metadata' in namespace
'uuid:2065d525-a365-4b45-b68e-bf45f0fba188' has invalid child element
'addressbookid' in namespace
'uuid:2065d525-a365-4b45-b68e-bf45f0fba188'. List of possible elements
expected: 'contact_us_email' in namespace
'uuid:2065d525-a365-4b45-b68e-bf45f0fba188'
But I know the Keyword has the correct Metadata assigned, (thats why I don't bother checking!). Shortened Tridion XML from a current keyword in question:
<tcm:Keyword>
<tcm:Data>
<tcm:MetadataSchemaxlink:type="simple"xlink:title="IP.Location.Metadata" xlink:href="tcm:49-2142-8" />
<tcm:Metadata>
<Metadata xmlns="uuid:2065d525-a365-4b45-b68e-bf45f0fba188">
<email>...</email>
<addressbookid>3</addressbookid>
<contact_us_email>...</contact_us_email>
<request_a_sample_email>...</request_a_sample_email>
<webinar_feedback_email>....</webinar_feedback_email>
</Metadata>
</tcm:Metadata>
<tcm:IsRoot>true</tcm:IsRoot>
</tcm:Data>
</tcm:Keyword>
Have I missed something can Keyword metadata not be updated in this way?
I guess I could look at the Core Service to update Keywords, but it seemed to to make sense to do everything within this application.
UPDATE
Order was key here, strangely!
The following code works:
ItemFields fields = k.MetadataFields;
System.Diagnostics.Debug.WriteLine(fields.Count);
string email = fields[1].value[1];
string contact = fields[3].value[1];
string request = fields[4].value[1];
string webinar = fields[5].value[1];
fields[1].value[1] = email;
fields[2].value[1] = ab.Id.ItemId;
fields[3].value[1] = contact;
fields[4].value[1] = request;
fields[5].value[1] = webinar;
k.Save(true);
Got caught out by the non-0-based index when getting/setting values and had to reassign existing fields back, in order.
Cheers
It seems that the order of the fields has changed in the Schema since that Component was created. At least the Schema expects contact_us_email in the position where you current have addressbookid.
There may be other changes, so I'd verify the order of fields in the Schema and make sure the Component(s) match, before you run your tool.
My problem is that I am trying to return a simple query that contains an object Story. The Story object has a UserId in the table which links to aspnet_users' UserId column. I have created a partial class for Story that adds the UserName property since it does not exist in the table itself.
The following query gets all stories; however, a pagination helper takes the query and returns only what's necessary once this is passed back to the controller.
public IQueryable<Story> FindAllStories(){
var stories = (from s in db.Stories
orderby s.DateEntered descending
select new Story
{
Title = s.Title,
StoryContent = s.StoryContent,
DateEntered = s.DateEntered,
DateUpdated = s.DateUpdated,
UserName = s.aspnet_User.UserName
}
);
return stories;
}
When the helper does a .count() on the source it bombs with the following exception:
"Explicit construction of entity type 'MyWebsite.Models.Story' in query is not allowed."
Any ideas? It's not a problem with the helper because I had this working when I simply had the UserName inside the Story table. And on a side note - any book recommendations for getting up to speed on LINQ to SQL? It's really kicking my butt. Thanks.
The problem is precisely what it tells you: you're not allowed to use new Story as the result of your query. Use an anonymous type instead (by omitting Story after new). If you still want Story, you can remap it later in LINQ to Objects:
var stories = from s in db.Stories
orderby s.DateEntered descending
select new
{
Title = s.Title,
StoryContent = s.StoryContent,
DateEntered = s.DateEntered,
DateUpdated = s.DateUpdated,
UserName = s.aspnet_User.UserName
};
stories = from s in stories.AsEnumerable() // L2O
select new Story
{
Title = s.Title,
StoryContent = s.StoryContent,
...
};
If you really need to return an IQueryable from your method and still need the Username of the user you can use DataContext.LoadOptions to eagerload your aspnet_user objects.
See this example.