KendoUI - can you create view models as functions - mvvm

With Knockout there are a couple of potential view model creation patterns, one is to use a literal:
var viewModel = {
firstname: ko.observable("Bob")
};
ko.applyBindings(viewModel );
and the other is to use a function:
var viewModel = function() {
this.firstname= ko.observable("Bob");
};
ko.applyBindings(new viewModel ());
As detailed in this question:
Difference between knockout View Models declared as object literals vs functions
My preference has always been to use a function because it essentially gives you a 'factory' allowing you to create multiple instances of the same view model.
With KendoUI, all the examples I have seen use a literal syntax:
var viewModel = kendo.observable({
firstname: "Bob"
});
kendo.bind(document.body, viewModel);
My question is, with Kendo is it possible to emulate the Knockout style of view model creation via functions? This would allow me to create multiple instances of the same view model, add 'private' functions, etc ...

After a bit of thought, I realised 'of course this is possible!' ...
ViewModel = function() {
this.firstname = "Bob";
return kendo.observable(this);
};
var viewModel = new ViewModel();
kendo.bind(document.body, viewModel);
Although you do have to be careful about references to 'this' within the constructor function because depending on when they are executed they may refer to the non-observable object:
ViewModel = function() {
firstname = "Bob";
this.doSomething = function() {
// here 'this' does not point to an obervable, but 'that' does!
that.set("forename", "Craig");
}
var that = kendo.observable(this);
return that;
};
var viewModel = new ViewModel();
kendo.bind(document.body, viewModel);

Related

Assign Mapped Object to Expression Result in LINQ to Entities

I have the following child object that we use an expression to map our 'entity' to our 'domain' model. We use this when specifically calling our ChildRecordService method GetChild or GetChildren:
public static Expression<Func<global::Database.Models.ChildRecord, ChildRecord>> MapChildRecordToCommon = entity => new ChildRecord
{
DateTime = entity.DateTime,
Type = entity.Type,
};
public static async Task<List<ChildRecord>> ToCommonListAsync(this IQueryable<global::Database.Models.ChildRecord> childRecords)
{
var items = await
childRecords.Select(MapChildRecordToCommon).ToListAsync().EscapeContext();
return items;
}
public async Task<List<ChildRecord>> GetChildRecords()
{
using (var uow = this.UnitOfWorkFactory.CreateReadOnly())
{
var childRecords= await uow.GetRepository<IChildRecordRepository>().GetChildRecords().ToCommonListAsync().EscapeContext();
return childRecords;
}
}
So that all works just fine. However we have another object that is a parent to that child, that in SOME cases, we also wish to get the child during the materialisation and mapping process.
In other words the standard object looks as such:
private static Expression<Func<global::Database.Models.Plot, Plot>> MapPlotToCommonBasic = (entity) => new Plot
{
Id = entity.Id,
Direction = entity.Direction,
Utc = entity.Utc,
Velocity = entity.Velocity,
};
However what I also want to map is the Plot.ChildRecord property, using the expression MapChildRecordToCommon I have already created. I made a second expression just to test this:
private static Expression<Func<global::Database.Models.Plot, Plot>> MapPlotToCommonAdvanced = (entity) => new Plot
{
ChildRecord = MapChildRecordToCommon.Compile() (entity.ChildRecord)
};
This fails:
System.NotSupportedException
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
Is there a way to reuse my existing expression for ChildRecord, to materialise the object of ChildRecord (ie. one to one/singular not multiple) on the Plot object? I think my trouble is caused by there being just one object and being unable to use the .Select(Map) method. I am not too great at expressions and have hit a wall with this.
For reference, there are actually up to 5 or 6 other child objects on the "Plot" object that I also want to make expressions for.
I resolved this by using the third party library LinqKit.
The library allowed the use of 2 methods, .AsExpandable() (which allows for the expressions to properly compile and be invoked as I understand), and .Invoke() as an extension method to an expression, rather than calling Expression.Invoke(yourexpression). I included a null check just in case.
My code now looks as follows:
public static async Task<List<Plot>> ToCommonListAsync(this IQueryable<global::Database.Models.Plot> plots)
{
var items = await
plots.AsExpandable().Select(MapPlotToCommon).ToListAsync().EscapeContext();
return items;
}
private static Expression<Func<global::Database.Models.Plot, Plot>> MapPlotToCommon = (entity) => new Plot
{
Id = entity.Id,
Direction = entity.Direction,
Utc = entity.Utc,
Velocity = entity.Velocity,
ChildRecord = entity.ChildRecord != null ? MapChildRecordToCommon.Invoke(entity.ChildRecord) : default
};
public static Expression<Func<global::Database.Models.ChildRecord, ChildRecord>> MapChildRecordToCommon = entity => new ChildRecord
{
DateTime = entity.DateTime,
Type = entity.Type,
};

Avoid lazyloader attribute

I´ve been looking for how avoid return a list without the attribute lazyLoader, I want to continue using the lazyLoader but I don´t want return the attribute when I return the whole list of my entity from my controller
I´m working with .NET core.
[
{
"lazyLoader": {},
"id": "id1"
"name": "name"
},
{
"lazyLoader": {},
"id": "id2",
"name": "name2"
}
]
You can do a select of you collection only retrieving the rest of the data.
That way your objects will not have the Navigation property at all.
db.YourCollection.Where(your condition)Select(x => new { id = x.id , name = x.name } );
In Entity Framework, if you have an object where one or more of its properties use lazy loading, check its runtime type name using GetType().Name. For an object of a Car class, for example, you will notice that the runtime type is actually something called CarProxy, which is a temporary in-memory type created by Entity Framework using reflection. This "fake" proxy class's base type is Car, and has all the original Car properties, but includes an extra one called LazyLoader for properties that may need it.
If you do further checking on this "fake" CarProxy type, you will also see that Assembly.IsDynamic = true, which is indicative that the class was created dynamically using reflection (see documentation):
var TheCar = DBContext.Cars.Find(1);
Console.WriteLine(TheCar.GetType().Assembly.IsDynamic.ToString()); //will echo "true"
Luckily, Newtonsoft.Json has an override on the JsonConvert.SerializeObject() method that allows us to provide a base type, so that the resulting JSON doesn't contain properties that don't exist in that type. So, to eliminate the LazyLoader property, just provide the object's BaseType as the type parameter:
var TheCar = DBContext.Cars.Find(1);
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType);
To make sure you don't get any circular reference loops when serializing (a very high probability when using lazy loading), call the serializer with the following setting:
var TheCar = DBContext.Cars.Find(1);
var Settings = new Newtonsoft.Json.JsonSerializerSettings
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType, Settings);
Note: This may only work on the first level deep when the serializer travels through the object. If there are yet more lazy-loading child properties of the object you provide to the serializer, the "LazyLoader" property may appear again. I haven't tested it so I can't say for sure.
I know this is old, but add
public boolean ShouldSerializeLazyLoader() { return false; }
to all the classes down the tree of the ones you want to serialize, and you will get a lazyloader free JSON.
Ref.: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
The checked answer for this question is just working for the root object, if we have many nested lazyloaded objects, this solution will not work.
Although the answer of #Marcello-Barbiani is correct but it is not a good way to add this function to all entities we have.
The best way is create a new ContractResolver derived from DefaultContractResolver and check if property is Lazyloader then skip it as below:
public class NonLazyloaderContractResolver : DefaultContractResolver
{
public new static readonly NonLazyloaderContractResolver Instance = new NonLazyloaderContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyName == "LazyLoader")
{
property.ShouldSerialize = i => false;
}
return property;
}
}
after that adding above class pass it through JsonSerializerSettings while serializing the object:
var json = JsonConvert.SerializeObject(newProduct, new JsonSerializerSettings() {
ContractResolver = new NonLazyloaderContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore });
and finally if you are using asp.net core or asp.net core webapi add this contract as default contractresolver in startup.cs file:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new NonLazyloaderContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});

How to Access the oData Model inside the Init Function of the Controller (UI5 Program)?

Can anyone tell how to access the oData Model(Manifest.json) inside the Init() of the Controller?
I tried to Access through Component.js. Tried Below Code in Component.js
var oModel = this.getModel("destinModel");
this.setModel(destinModel,"Model");
in Controller Init() Function--
var oComponent = this.getOwnerComponent();
var oModel = oComponent.getModel("Model");
This didn't work when I used it inside Init Function, but it worked inside onAfterRendering().
I need to access the Model Inside the Init() of the Controller.. if I can't please suggest me any alternative ways to access the Model..
I have also noticed that the model is being passed to the view only after the init function of your view has already been executed. But when the init function of your view is executed, the model does already exist in the component. So instead of this.getModel(), you could use this.getComponent().getModel() to access it. E.g.:
onInit: function() {
this.component = this.getComponent();
this.model = this.component.getModel("destinModel");
this.setModel(this.model, "Model");
},
To be able to actually access the model from your init function (if you plan to do so), you will have to wait until the model's metadata has been loaded. To run code as soon as the metadata has been loaded, the ODataModel provides the metadataLoaded function. This function returns a promise to which you can hook up your functionality. E.g.:
onInit: function() {
this.component = this.getComponent();
this.model = this.component.getModel("destinModel");
this.setModel(this.model, "Model");
this.model.metadataLoaded().then(function() {
alert("We have the model to our disposal at this point");
}.bind(this));
},

Entity Framework 7 multiple levels of child tables

I'm just getting started with EF7 (CORE) and am struggling to find the right implementation of the following. Say I have a Table with multiple child tables, which in turn have grandchild tables (and these in turn have foreign key tables). If I wanted access to everything I'd need something like this
TABLE_A.Include(c => c.TABLE_B).ThenInclude(co => co.TABLE_C)
.ThenInclude(coi => coi.TABLE_D)
.ThenInclude(coia => coia.TABLE_E)
.Include(c => c.TABLE_B).ThenInclude(co => co.TABLE_F)
.ThenInclude(coa => coa.TABLE_G)
.ThenInclude(coaAcc => coaAcc.TABLE_H)
.ThenInclude(coaAccInt => coaAccInt.TABLE_D)
.ThenInclude(coaAccIntAgent => coaAccIntAgent.TABLE_E)
Now I understand the necessity for chaining the includes to include all of my child tables...but I look at the SQL it fires behind the scenes and its firing off 11 SQL statements. This seems terribly inefficient.
Is this the best way to be doing this? I have now received a new requirement to add 3 more child tables to TABLE_B...so I'll need more includes..and hence more selects running behind the scenes.
I understand the logic behind what I'm doing..and understand lazy loading isn't currently supported in EF7, but this doesn't seem like a very efficient way of doing things when I could write a stored procedure that does it in one go.
Are there best practices for things like this or something I'm not grasping about how to use EF7 to do what I need?
Any help or guidance would be much appreciated!
Thanks
add this extension method to your project, Load method exist in ef 6.x, but not implemented yet in ef core:
public static void Load<TSource, TDestination>(this EntityEntry<TSource> entry, Expression<Func<TSource, IEnumerable<TDestination>>> path, Expression<Func<TDestination, TSource>> pathBack = null) where TSource : class where TDestination : class
{
var entity = entry.Entity;
var context = entry.Context;
var entityType = context.Model.FindEntityType(typeof(TSource));
var keys = entityType.GetKeys();
var keyValues = context.GetEntityKey(entity);
var query = context.Set<TDestination>() as IQueryable<TDestination>;
var parameter = Expression.Parameter(typeof(TDestination), "x");
PropertyInfo foreignKeyProperty = null;
if (pathBack == null)
{
foreignKeyProperty = typeof(TDestination).GetProperties().Single(p => p.PropertyType == typeof(TSource));
}
else
{
foreignKeyProperty = (pathBack.Body as MemberExpression).Member as PropertyInfo;
}
var i = 0;
foreach (var property in keys.SelectMany(x => x.Properties))
{
var keyValue = keyValues[i];
var expression = Expression.Lambda(
Expression.Equal(
Expression.Property(Expression.Property(parameter, foreignKeyProperty.Name), property.Name),
Expression.Constant(keyValue)),
parameter) as Expression<Func<TDestination, bool>>;
query = query.Where(expression);
i++;
}
var list = query.ToList();
var prop = (path.Body as MemberExpression).Member as PropertyInfo;
prop.SetValue(entity, list);
}
public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class
{
var state = context.Entry(entity);
var metadata = state.Metadata;
var key = metadata.FindPrimaryKey();
var props = key.Properties.ToArray();
return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray();
}
then whenever you need each of navigation properties, before use first call load (just once for any navigation properties) method as fallowing:
//for first item
var item = TABLE_A.First();
context.Entry(item ).Load(b => b.TABLE_B);
Depending on your use case, can Include or ThenInclude some of navigation in first query that load TABLE_A.
Load extension method Source Link with more examples

Sequelize Hooks - does the funcs expose the Models as in the associations?

When creating a hook I want to know if the models variable is exposed in the function like in the assosiations:
...
classMethods: {
associate: function ( models ) {
users.belongsTo( models.roles, { foreignKey: 'role' } );
}
}
...
What I'd like to do is to update the a value of another model, first I have to update the current amount of product adding the amount purchased (any tips?), so, I need the models var.
hooks : {
afterCreate: function ( inventory, options ) {
//What does the `options` value has?
}
}
One workaround suggested was to simply require the model...
Also I would like to know if afterCreate would work for bulkCreate? Or does it necessary has to be afterBulkCreate?
afterCreate is triggered after each creation. afterBulkCreate is triggered after the whole set has been created. So if you are creating 10 items, afterCreate would be called 10 times, after each item was created. But afterBulkCreate would only be called once.
This doesn't seem to be documented throughly enough but I'd suggest just creating a hook and then doing console.log(arguments) inside the hook to see which arguments are beeing passed in. But I'd suggest to just require the model like you said.
The models variable is not exposed in the function. The solution I found when I need to update the value of another model is the following:
Define a function to get the hooks that receives the models:
var getHooks = function(models) {
return {
afterCreate: function(item, options) {
// Can access the models:
models.roles.create({...});
},
beforeCreate: function(item, options) {
// Code here
}
};
};
And set the hooks functions in the associate method:
classMethods: {
associate: function ( models ) {
users.belongsTo( models.roles, { foreignKey: 'role' } );
var hooks = getHooks(models);
for(var name in hooks) {
users.addHook(name, hooks[name]);
}
}
}