Get WorkflowDesigner from a ModelItem - workflow-foundation-4

I am trying to create a custom IExpressionEditor. In order to new one up I need a WorkflowDesigner, All I have is the ModelItem representing my custom activity. Is it possible to access the WorkflowDesigner from a given ModelItem?
List<ModelItem> variables = new List<ModelItem>();
List<ModelItem> nameSpaces = new List<ModelItem>();
// get the activity from the datacontext
CustomActivityDesigner cad = this.DataContext as CustomActivityDesigner;
// try to get the variables
// look for variables collection cant seem to find them
ModelProperty mp = cad.ModelItem.Properties["Variables"];
if(mp != null && mp.PropertyType == typeof(Collection<Variable>))
{
mp.Collection.ToList().ForEach(i => variables.Add(i));
}
// get name spaces
ModelProperty mp2 = cad.ModelItem.Properties["NameSpaces"];
if(mp2 != null && mp2.PropertyType == typeof(Collection<NameSpace>))
{
mp2.Collection.ToList().ForEach(i => nameSpaces.Add(i));
}
// finally need the WorkflowDesigner object
WorkflowDesigner designer = Modelitem.Root....??? as WorkflowDesigner
// now we have what we need we can create the IExpressionEditor
CustomExpressionEditior ce = new CustomExpressionEditior(designer, variables, nameSpaces)

Following the Using a Custom Expression Editor as reference, it seems you should be able to create a Custom Expression Service (which will be creating the Expression Editor instances) and register it to the Services collection on the WorkflowDesigner.
Once it's registered in the WorkflowDesigner's Services collection, you'll be able to:
Get the editing context for the ModelItem by using ModelItemExtensions.GetEditingContext
Access the Services property of the returned EditingContext
Retrieve the Custom Expression Service you registered on the WorkflowDesginer
Hope it helps!

Related

Adding users and attributes programatically in Concrete5 version 8

Hi I have recently followed some documentation to create new users from a csv file programatically. According to the Concrete5 docs/api there was method called getByID( $uID ) but this has since be deprecated!
I am creating a new user like so:
$userRegistration = Core::make('user/registration');
$file = fopen("test-users.csv","r");
while (($data = fgetcsv($file)) !== FALSE) {
echo "email address " . $data[0];
$userRegistration->create([
'uName' => $data[0],
'uPassword' => $data[1],
'uEmail' => $data[2],
'uIsValidated' => true,
]);
}
However if I want to add a value to an existing non-core attribute for instance lets call it user_county then how would I change this after programatically adding the user? I may need to do this for several user attributes as well so the values would need to come from the CSV and automatically be looped through to apply the correct value to the corresponding attribute whether it is blank or filled.
The create() method will return a UserInfo object (Concrete\Core\User\UserInfo) after successfully adding a new user. With the returned UserInfo object, you can use the setAttribute() method to set your custom user attribute.
Make sure that you have created the customer user attribute first and check that it is available before setting it, otherwise setting it will throw an error. I believe you can do this using Concrete\Core\Attribute\Key\UserKey::getByHandle('my_user_attribute') and seeing if it returns an object.
The create() method is in the RegistrationService class:
https://github.com/concrete5/concrete5/blob/develop/concrete/src/User/RegistrationService.php#L51-L140

How does Entity Framework decide whether to reference an existing object or create a new one?

Just for my curiosity (and future knowledge), how does Entity Framework 5 decide when to create a new object vs. referencing an existing one? I might have just been doing something wrong, but it seems that every now and then if I do something along the lines of:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = currParent;
db.SaveChanges();
}
EF will create a new Parent in the database, basically a copy of the currParent, and then set the Parent_ID value of currThing to that copy. Then, if I do it again (as in, if there's already two of those parents), it won't make a new Parent and instead link to the first one. I don't really understand this behavior, but after playing around with it for a while something like:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = db.Parents.Where(p => p.ID == currParent.ID).First();
db.SaveChanges();
}
seemed to fix the problem. Is there any reason this might happen that I should be aware of, or was there just something weird about the way I was doing it at the time? Sorry I can't be more specific about what the exact code was, I encountered this a while ago and fixed it with the above code so I didn't see any reason to ask about it. More generally, how does EF decide whether to reference an existing item instead of creating a new one? Just based on whether the ID is set or not? Thanks!
If your specific instance of your DBContext provided that specific instance of that entity to you, then it will know what record(s) in the database it represents and any changes you make to it will be proper to that(those) record(s) in the database. If you instantiate a new entity yourself, then you need to tell the DBContext what exactly that record is if it's anything but a new record that should be inserted into your database.
In the special scenario where you have multiple DBContext instances and one instance provides you this entity but you want to use another instance to work with and save the entity, then you have to use ((IObjectContextAdapter)firstDbContext).ObjectContext.Detach() to orphan this entity and then use ((IObjectContextAdapter)secondDbContext).ObjectContext.Parents.Attach() to attach it (or ApplyChanges() if you're also editing it - this will call Attach for you).
In some other special scenarios (your object has been serialized and/or you have self-tracking entities), some additional steps may be required, depending on what exactly you are trying to do.
To summarize, if your specific instance of your DBContext is "aware" of your specific instance of an entity, then it will work with it as if it is directly tied to that specific row in the database.

writing a library class properly

This is my very first library class that i am writing and i feel like i need to load up on that topic but cannot find the best sources. I have a web forms project that uploads a pdf and creates a qrcode for it and places it in the document. I need to create a library but don't know where to start or the exact structure. Every method it's own subclass in the library class? or can i have them all in one and what is a professional way of going about this.
This is party of my web forms application that i need to create a library for:
void UpdateStudentSubmissionGrid()
{
var usr = StudentListStep2.SelectedItem as User;
var lib = AssignmentListStep2.SelectedItem as Library;
if (usr == null || lib == null) return;
using (var dc = new DocMgmtDataContext())
{
var subs =
(from doc in dc.Documents
where doc.OwnedByUserID == usr.ID && doc.LibraryID == lib.ID
select new {DocID = doc.ID, Assignment = doc.Library.Name, Submitted = doc.UploadDT})
.OrderByDescending(c => c.Submitted)
.ToList();
StudentSubmissionGrid.DataSource = subs;
}
}
How do i start with this method?
By the looks of things you are using this function for a single webpage. You can call that function from any event i.e. user hits submit button. On the. Click the button and it will create a onclick event. Call the code from inside there UpdateStudentSubmissionGrid(); Just make sure the function is not nested inside another event or function. Webforms is already a class, you are just placing a function within the class.

Saving changes of Entity Framework in Asp.Net

I have created an entity Appraiser and there are methods to select values, display data etc.
Now I want to save the changes made after data is displayed, I have a button named SAVE, which will be used to save changes.
I am not able to get how to save the changes of this Entity?
Entity name is Appraiser, and I have created methods like get AppriaserDetails etc in DAL, BL and used them in aspx.cs.
This is my code:
public void UpdateData(Appraiser appId)
{
var Appsave = context.Appraisers.FirstOrDefault(App => App.AppraiserId == appId.AppraiserId);
Appsave.AppraiserName = appId.AppraiserName;
Appsave.AppraiserPhones = appId.AppraiserPhones;
Appsave.AppraiserAppraiserCompanyId = appId.AppraiserAppraiserCompanyId;
Appsave.Address = appId.Address;
Appsave.City = appId.City;
Appsave.ProvinceState = appId.ProvinceState;
Appsave.Email = appId.Email;
context.SaveChanges();
}
If u want to insert new record, then can use
MyContext.Appraisers.AddObject(appraiserEntityObject);
MyContext.SaveChanges();
In case of update
if (appraiserEntityObject.EntityState == EntityState.Detached)
{
// In case of web, we got an existing record back from the browser. That object is not attached to the context yet.
MyContext.Appraisers.Attach(appraiserEntityObject);
MyContext.ObjectStateManager.ChangeObjectState(appraiserEntityObject, EntityState.Modified);
}
MyContext.SaveChanges();
Here MyContext is ur ObjectContext

Accessing the object/row being edited in Dynamic Data

I'm modifying the "Edit.aspx" default page template used by ASP.NET Dynamic Data and adding some additional controls. I know that I can find the type of object being edited by looking at DetailsDataSource.GetTable().EntityType, but how can I see the actual object itself? Also, can I change the properties of the object and tell the data context to submit those changes?
Maybe you have found a solution already, however I'd like to share my expresience on this.
It turned out to be a great pita, but I've managed to obtain the editing row. I had to extract the DetailsDataSource WhereParameters and then create a query in runtime.
The code below works for tables with a single primary key. If you have compound keys, I guess, it will require modifications:
Parameter param = null;
foreach(object item in (DetailsDataSource.WhereParameters[0] as DynamicQueryStringParameter).GetWhereParameters(DetailsDataSource)) {
param = (Parameter)item;
break;
}
IQueryable query = DetailsDataSource.GetTable().GetQuery();
ParameterExpression lambdaArgument = Expression.Parameter(query.ElementType, "");
object paramValue = Convert.ChangeType(param.DefaultValue, param.Type);
Expression compareExpr = Expression.Equal(
Expression.Property(lambdaArgument, param.Name),
Expression.Constant(paramValue)
);
Expression lambda = Expression.Lambda(compareExpr, lambdaArgument);
Expression filteredQuery = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, query.Expression, lambda);
var WANTED = query.Provider.CreateQuery(filteredQuery).Cast<object>().FirstOrDefault<object>();
If it's a DD object you may be able to use FieldTemplateUserControl.FindFieldTemplate(controlId). Then if you need to you can cast it as an ITextControl to manipulate data.
Otherwise, try using this extension method to find the child control:
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
T found = startingControl.FindControl(id) as T;
if (found == null)
{
found = FindChildControl<T>(startingControl, id);
}
return found;
}
I found another solution, the other ones did not work.
In my case, I've copied Edit.aspx in /CustomPages/Devices/
Where Devices is the name of the table for which I want this custom behaviour.
Add this in Edit.aspx -> Page_Init()
DetailsDataSource.Selected += entityDataSource_Selected;
Add this in Edit.aspx :
protected void entityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
Device device = e.Results.Cast<Device>().First();
// you have the object/row being edited !
}
Just change Device to your own table name.

Resources