update a custom property for a member as admin in c# - ektron

I have added a custom property for members and would like to create a routine that loops through all the members and initializes the custom property.
Im using Ektron Version 8.5 sp1
Here are the two methods that I have tried:
Method 1 - This method does not return the userData object
var userManager = new Ektron.Cms.Framework.User.UserManager(Ektron.Cms.Framework.ApiAccessMode.Admin);
var userData = userManager.GetItem(userManager.UserId, true);
userData.CustomProperties["Year 7 Year"].Value = newYear7Year;
userManager.Update(userData);
Method 2 - Im concerned this won't work because I don't specify the ApiAccessMode to be Admin
var commonApi = new Ektron.Cms.CommonApi();
var userApi = new Ektron.Cms.API.User.User();
var userData = userApi.GetUser(commonApi.UserId, false, false);
userData.CustomProperties["Year 7 Year"].Value = newYear7Year;
userApi.UpdateUser(userData);
How should I update the Member?

I have custom properties that I update. I update them when the user creates an account but I don't think this is any different.
I don't use the CommonApi.
Here is the basics of what I do:
Ektron.Cms.API.User.User userApi = new Ektron.Cms.API.User.User();
Ektron.Cms.UserData userData = userApi.GetUser(PUT_USER_ID_HERE);
userData.CustomProperties[keyName].Value = value;
userApi.UpdateUser(userData);
The value of PUT_USER_ID_HERE determines which user will be updated.
I didn't need to do anything special with an Admin User or anything like that so hopefully it won't be a problem for you either.

Related

Update Document with external object

i have a database containing Song objects. The song class has > 30 properties.
My Music Tagging application is doing changes on a song on the file system.
It then does a lookup in the database using the filename.
Now i have a Song object, which i created in my Tagging application by reading the physical file and i have a Song object, which i have just retrieved from the database and which i want to update.
I thought i just could grab the ID from the database object, replace the database object with my local song object, set the saved id and store it.
But Raven claims that i am replacing the object with a different object.
Do i really need to copy every single property over, like this?
dbSong.Artist = songfromFilesystem.Artist;
dbSong.Album = songfromFileSystem.Album;
Or are there other possibilities.
thanks,
Helmut
Edit:
I was a bit too positive. The suggestion below works only in a test program.
When doing it in my original code i get following exception:
Attempted to associate a different object with id 'TrackDatas/3452'
This is produced by following code:
try
{
originalFileName = Util.EscapeDatabaseQuery(originalFileName);
// Lookup the track in the database
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
if (dbTracks.Count > 0)
{
track.Id = dbTracks[0].Id;
_session.Store(track);
_session.SaveChanges();
}
}
catch (Exception ex)
{
log.Error("UpdateTrack: Error updating track in database {0}: {1}", ex.Message, ex.InnerException);
}
I am first looking up a song in the database and get a TrackData object in dbTracks.
The track object is also of type TrackData and i just put the ID from the object just retrieved and try to store it, which gives the above error.
I would think that the above message tells me that the objects are of different types, which they aren't.
The same error happens, if i use AutoMapper.
any idea?
You can do what you're trying: replace an existing object using just the ID. If it's not working, you might be doing something else wrong. (In which case, please show us your code.)
When it comes to updating existing objects in Raven, there are a few options:
Option 1: Just save the object using the same ID as an existing object:
var song = ... // load it from the file system or whatever
song.Id = "Songs/5"; // Set it to an existing song ID
DbSession.Store(song); // Overwrites the existing song
Option 2: Manually update the properties of the existing object.
var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.Artist = song.Artist;
existingSong.Album = song.Album;
Option 3: Dynamically update the existing object:
var song = ...;
var existingSong = DbSession.Load<Song>("Songs/5");
existingSong.CopyFrom(song);
Where you've got some code like this:
// Inside Song.cs
public virtual void CopyFrom(Song other)
{
var props = typeof(Song)
.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(p => p.CanWrite);
foreach (var prop in props)
{
var source = prop.GetValue(other);
prop.SetValue(this, source);
}
}
If you find yourself having to do this often, use a library like AutoMapper.
Automapper can automatically copy one object to another with a single line of code.
Now that you've posted some code, I see 2 things:
First, is there a reason you're using the Advanced.DocumentQuery syntax?
// This is advanced query syntax. Is there a reason you're using it?
var dbTracks = _session.Advanced.DocumentQuery<TrackData, DefaultSearchIndex>().WhereEquals("Query", originalFileName).ToList();
Here's how I'd write your code using standard LINQ syntax:
var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
.Where(t => t.Query == escapedFileName)
.Select(t => t.Id);
if (existingTrackId != null)
{
track.Id = existingTrackId;
_session.Store(track);
_session.SaveChanges();
}
Finally, #2: what is track? Was it loaded via session.Load or session.Query? If so, that's not going to work, and it's causing your problem. If track is loaded from the database, you'll need to create a new object and save that:
var escapedFileName = Util.EscapeDatabaseQuery(originalFileName);
// Find the ID of the existing track in the database.
var existingTrackId = _session.Query<TrackData, DefaultSearchIndex>()
.Where(t => t.Query == escapedFileName)
.Select(t => t.Id);
if (existingTrackId != null)
{
var newTrack = new Track(...);
newTrack.Id = existingTrackId;
_session.Store(newTrack);
_session.SaveChanges();
}
This means you already have a different object in the session with the same id. The fix for me was to use a new session.

Get property names present in a breeze entity

After I execute breeze query as shown below:
var breezeQuery = function(){
var query = EntityQuery.from('TableA')
.inlineCount();
function querySuceeded(data) {
//data.results[0] contains the entity
}
manager.executeQuery(query)
.then(querySuceeded)
}
I get the entity in data.results[0] which contains properties as well as other information like entityAspect etc.
How can I get the property names present in a breeze entity ?
Use the MetadataStore. Something like this:
var tableAType = manager.metadataStore.getEntityType("TableA");
var dataProperties = tableAType.dataProperties;
var navigationProperties = tableAType.navigationProperties;
or from an instance of a entity ( not a projection), since every entity will have an 'entityType' property you can also do this:
var tableAType = tableAInstance.entityType;
var dataProperties = tableAType.dataProperties;
var navigationProperties = tableAType.navigationProperties;
Also see: http://www.breezejs.com/sites/all/apidocs/classes/EntityType.html
Object.keys(data.result[0]) is the vanilla JavaScript way to get all properties of the data.result[0] object. Just saying.
Jay's way of course winnows those down to the properties monitored by Breeze, the persisted properties in particular. That's probably what you meant :-)

Sitecore Glass mapper GetItem<TypeName>(guid) always return null

I saw a related question:
Sitecore Glass Mapper always null
But unfortunately it does not give a solution for my case.
Here goes a code snippet:
var db = Factory.GetDatabase("master");
var context = new SitecoreContext();
// the ID of Needed item
var g = new Guid("{F21C04FE-8826-41AB-9F3C-F7BDF5B35C76}");
// just to test if it's possible to fetch item using db.GetItem
var i = db.GetItem(new ID(g), Language.Current, Sitecore.Data.Version.Latest);
// Grab item
var t = context.GetItem<Article>(g);
In the code above:
i is not null
t is null
Article is the simple class like:
[SitecoreType(TemplateId = "{4C4EC1DA-EB77-4001-A7F9-E4C2F61A9BE9}")]
public class Article
{
[SitecoreField(FieldName = "Title")]
public string Title { get; set; }
}
There are only one language installed in Sitecore - en, it has been specified in the web.config in the items as well.
Also I have added GlassMapperSc.Start(); to Application_Start in the Global.asax.cs and added my assembly to the list of included assemblies via var attributes = new AttributeConfigurationLoader(new[] { "Assembly.Name" }); and I succeeded to find my class in the SitecoreContext mappings.
It does not looks like a language issue, as stated in the link provided in the very beginning. And I'm struggling with it already for a pretty long time, but no luck...
Thank You!
I just noticed that you are using master db for the Sitecore DB and SitecoreContext for Glass.
The SitecoreContext class will use the database that is defined by the Sitecore.Context.Database property at runtime. This probably means that it is using the web database.
Can you check that you have published the item to the web database or instead using:
var context = new SitecoreService("master");

Difficulty passing object from one controller to anothher

I am trying to pass an object from one controller to another controller, but it is not behaving in the way that I would like it to. In the following ApplicantMainController, I am instantiating an object called ApplicationQuestions (which contains a List<ApplicationQuestion> object as one of its members) and then attempting to pass it via the RedirectToAction method call:
public ActionResult FormAction(FormCollection collection)
{
if (collection["cmdSearch"] != null)
{
// more code above...
ApplicationQuestions questions = new ApplicationQuestions();
MultipleChoiceQuestion q1 = new MultipleChoiceQuestion("Can you lift 50 pounds?");
MultipleChoiceQuestion q2 = new MultipleChoiceQuestion("Are you at least 18 years of age?");
MultipleChoiceQuestion q3 = new MultipleChoiceQuestion("Are you legally able to work in the US?");
MultipleChoiceQuestion q4 = new MultipleChoiceQuestion("Have you ever been convicted of a felony?");
q1.AddPossibleAnswer(1, new Answer("Yes", true));
q1.AddPossibleAnswer(2, new Answer("No", false));
q2.AddPossibleAnswer(1, new Answer("Yes", true));
q2.AddPossibleAnswer(2, new Answer("No", false));
q3.AddPossibleAnswer(1, new Answer("Yes", true));
q3.AddPossibleAnswer(2, new Answer("No", false));
q4.AddPossibleAnswer(1, new Answer("Yes", false));
q4.AddPossibleAnswer(2, new Answer("No", true));
questions.AddQuestion(q1);
questions.AddQuestion(q2);
questions.AddQuestion(q3);
questions.AddQuestion(q4);
// not sure how to pass the object here??
return RedirectToAction("Apply", "ApplicantApply", new { model = questions });
}
}
When I redirect to the controller, it appears to make it:
private ApplicationQuestions m_questions;
// more code ...
public ActionResult Apply(ApplicationQuestions questions)
{
m_questions = questions;
return RedirectToAction("NextQuestion", "ApplicantApply");
}
However, though the reference is now bound to the parameter passed to the Apply method, the debugger tells me that the reference to the collection questions does not contain any elements, though clearly the caller passed a collection with four elements. I think I am misunderstanding how this works -- what is the proper way to communicate objects between controllers like this?
One option is to use TempData to hold the object during the redirect.
TempData["MyCoolData"] = questions;
return RedirectToAction("Apply", "ApplicantApply");
Then grab the object out of TempData in the other action:
m_questions = (ApplicationQuestions)TempData["MyCoolData"];
See this question and its answers for more information.

Handle navigation properties when adding new object to entity model

I have the following data model:
I am writing a WCF service that needs to support adding new Report:
public bool CreateNewReport(Report report)
{
MyEntities context = new MyEntities();
context.AddToReports(Report);
context.SaveChanges();
}
So my method gets a report object that was made on the client and adds it to the database throught the data context. (all of the members are included in the DataContract)
My question is regarding navigation properties.
Do the client also needs to create a user object and put it in the new report object before sending it ?
What is the best way to approach this ? one way i think of is adding a UserId field in the ReportEntity
when a new report is inserted, how do i update the UserEntity Report nav property that with the new Report ?
Thanks.
If you import your database, generate navigation properties (the properties in your picture) AND foreign id properties (then you have for example an User and UserID property in your report class). This way you can set the UserID in your client and send it to the server and add it with AddToReports... If you send the whole user object you have to attach it to the entity context otherwise the user will be created once again...
Attach the referenced user: (but it's better to send the user only by id)
public bool CreateNewReport(Report report)
{
using (MyEntities context = new MyEntities())
{
context.AddToReports(Report);
context.Users.Attach(report.User);
context.SaveChanges();
}
}
To change the report of a user:
public bool ChangeUserToNewReport(int userid, Report newReport)
{
using (MyEntities context = new MyEntities())
{
var user = context.Users.Single(u => u.ID = userid);
user.Report = newReport;
context.SaveChanges();
}
}
For an existing report:
public bool ChangeUserReport(int userid, Report existingReport)
{
using (MyEntities context = new MyEntities())
{
context.Reports.Attach(existingReport);
var user = context.Users.Single(u => u.ID = userid);
user.Report = existingReport;
context.SaveChanges();
}
}
This is a sample how your model should look like. Double click on the association line to open the dialog. You can see that the Person and PersonID properties are the same. If you create your model like this, VS should generate the correct SQL.