Multiple Compute fields in KnockoutMVC Sub-Models - knockout-mvc

KnockoutMVC 2.10, MVC 4.0, C# 5.
Working from one of the examples on the main site (Computed fields in Sub Models). I am having a problem and wondered if anyone could help. In the code below, the computed Message field updates fine, based on two text boxes associated with Caption and Value respectively. However, as soon as I un-comment the second [Computed] attribute, with no other changes to the View (or any other code), it stops working. Incidentally, in the same project, in the main model I have tried 2 computed fields and they worked fine. Is this a limitation of sub models (ie only one computed field allowed)?
Thanks
Rob
public class InnerComputedSubModel
{
public decimal Caption { get; set; }
public decimal Value { get; set; }
public decimal Caption2 { get; set; }
public decimal Value2 { get; set; }
[Computed]
public decimal Message
{
get { return Caption * Value; }
}
//[Computed]
public decimal Message2
{
get { return Caption2 * Value2 * 20; }
}
}
public class InnerComputedModel
{
public InnerComputedSubModel SubModel { get; set; }
}

KnockoutMVC does support multiple Computed properties however it has some bugs when using decimal values inside Computed properties.
One possible workaround is to don't use decimals in your Computed but float or double away there is no JavaScript equivalent of the C# decimal type.
So the following code should work fine:
public class InnerComputedSubModel
{
public double Caption { get; set; }
public double Value { get; set; }
public double Caption2 { get; set; }
public double Value2 { get; set; }
[Computed]
public double Message
{
get { return Caption * Value; }
}
[Computed]
public double Message2
{
get { return Caption2 * Value2 * 20; }
}
}

Related

Is there a way to have EF Core populate navigation properties before the change tracker snapshots values?

I have an order model in my core with a collection of (abstract base) OrderLines which can be either a NoteLine or an ItemLine. Each ItemLine has various pricing details relevant to that specific line.
public class Order : IEntity<int>
{
public int Id { get; private set; }
protected ICollection<OrderLine> _Lines;
public IEnumerable<OrderLine> Lines => _Lines.AsEnumerable();
public decimal TotalSellEx
{
get => _Lines.OfType<ItemLine>().Sum(l => l.TotalSellEx);
protected set { }
}
}
public class NoteLine
{
public string Note { get; protected set; }
}
public class ItemLine
{
public int StockId { get; protected set; }
public decimal TotalSellEx => ItemSellEx * Quantity;
public decimal ItemSellEx { get; protected set; }
public decimal GrossProfit { get; protected set; }
public int Quantity { get; protected set; }
}
public abstract class OrderLine
{
public decimal LineNumber { get; protected set; }
}
public class OrderConfiguration : EntityConfiguration<Order, int>
{
public override void Configure(EntityTypeBuilder<Statement> builder)
{
base.Configure(builder);
builder.HasMany(o => o.Lines)
.WithOne(o => o.Statement);
builder.Navigation(o => o.Lines)
.AutoInclude();
}
}
My Order model then uses a getter only property to keep a rolling sum of the total values as the list is manipulated by various functions and is successfully persisted to the database due to the empty setter to get around EF Core's need for a setter.
The problem occurs when I pull the record out of the database and change tracker kicks in. It seems to be that the snapshot of this model is created before navigation properties are populated so the total value is always 0 in the change tracker.
This isn't a big problem until the total value is modified in such a way that it becomes 0 properly. In which case EF Core doesn't see a change and doesn't populate the UPDATE statement with this column. At this point any projections containing this property are wrong, showing the previous value before it was set back to 0.
For the record, it always seems that once the object is retrieved the lines are all there, just not during change tracking snapshotting.
Is there a way to get around this behaviour? Or do I have to settle for bandaid work arounds?

How to manage DTO Implementaion for Rest-Api in .NET CORE? Alternatives?

I have a quite big query in my WebApi which filters data from different models to send them in a DTO Object to FrontEnd(Angular).
I think DTO could be the right approach because it isn't neccessary for the frontend to get all parameters from all models.
My problem consists in from mapping the DTO Object back to my WebApi Models.
I tried Automapper from NugetPackages but it didn't work. I also heard that AutoMapper isn't the right choice when projects are getting bigger and bigger.
Below is the Code for my DTO object, query and models:
public class ApplicationSettingsDto
{
public string KeyName { get; set; }
public string Wert { get; set; }
public string DefaultValue { get; set; }
public string Description { get; set; }
}
Models:
public partial class ApplicationSettings
{
public string KeyName { get; set; }
public string Wert { get; set; }
public int Typ { get; set; }
public string DisplayOrder { get; set; }
}
public partial class ApplicationSettingsDefaults
{
public Guid Id { get; set; }
public string KeyName { get; set; }
public string Value { get; set; }
public int ProduktOption { get; set; }
}
public partial class Text
{
public string KeyName { get; set; }
public string Sprache { get; set; }
public string Text1 { get; set; }
public DateTime LetzteAenderung { get; set; }
}
Query:
public IQueryable Description()
{
int produktOption = GetProduktOption();
var query = from appl in _repositoryContext.ApplicationSettings
from text in _repositoryContext.Text
from defaults in _repositoryContext.ApplicationSettingsDefaults
//filter DefaultValues
where appl.KeyName.Equals(defaults.KeyName) &&
(defaults.ProduktOption.Equals(produktOption) || defaults.ProduktOption.Equals(65535))
//Filter TextValues
where EF.Functions.Like(text.KeyName, "%" + appl.KeyName) ||
EF.Functions.Like(text.KeyName, "%" + appl.KeyName + "$Descr")
where EF.Functions.Like(text.Sprache, "de-DE")
select new ApplicationSettingsDto()
{
KeyName = appl.KeyName,
Wert = appl.Wert,
DefaultValue = defaults.Value,
Description = text.Text1
}
into output orderby output.KeyName select output;
return query;
}
So this question is not about an detailed implementation, it's only about recommendations for implementing DTO because mapping can be a pain in the *ss, like in my example.
I'm open to new ideas or patterns I don't know yet to try to manage problems like this.
Thanks in Advance ;)
This question is likely to be closed as you have working code, but my recommendation, after years of having tried AutoMapper, reflection based mappings, and hand-written mappings, that you should just stick with what is simplest and works.
You typically have to write the mapping logic for your DTOs once. The code you would write is legible and straightforward. When you move that to AutoMapper, you now end up having an often unrelated and less legible piece of code for something very, very simple.
In the event that you need the mapping logic in another function, extract it to a separate method. In the event that you need it in a separate class, promote that mapping function to a static method on your DTO.
Most of my mapping code looks like:
// Some controller code
da.GetStudents().Select(Map); // Map is the function below
In the controller, the following method is defined:
public StudentDto Map(Student student)
{
if (student == null) return null;
return new StudentDto
{
FirstName = student.FirstName,
...
};
}
Hope that helps.

How to setup my code as DB First in an ORM

I have looked at using EF, nHibernate and Dapper/Dapper.SimpleCRUD. In none of them can I figure out how to represent my use case in regards to my database (SQL Server 2012) model. I am building an ASP.NET website with a grid in C# 4.0/.NET 4.0 (due to technical limitations) that will have CRUD capabilities, with the initial state of the grid being set by dropdowns.
My two tables are set up as such:
Address_Book
|_[EntryID]
|_[Last_Name]
|_[First_Name]
|_[Title]
|_[Office_Num]
|_[Cell_Num]
|_[Home_Num]
|_[Email_Address]
|_[Special_Info]
|_[hr24_Emails]
|_[hr48_Emails]
|_[RM_Emails]
|_[Prestige_Emails]
|_[GEB_Emails]
|_[LAW_Emails]
Distribution
|_[Brand]
|_[Location_Mnemonic]
|_[Location_Code_Numeric]
|_[EntryID]
|_[Division_Mnemonic]
|_[Region_Mnemonic]
|_[Zone_Mnemonic]
|_[District_Mnemonic]
|_[Key]
With a many-to-one relationship between Distribution and Address_Book where Address_book.EntryID = Distribution.EntryID.
Any help with how to set this up would be appreciated. I am having issues managing the CRUD operations manually, so I thought an ORM would help, but I cannot figure it out. Any help is appreciated.
Thanks in advance!
The whole .net CRUD thing is a big realm with a lot of flavors and ways of doing the work. And while I don't know exactly where you are at with this, the following my help out. In my experience EF can handle relationships quite well, though the whole EF learning process is a bit steep and I've shied away from it. I typically use Dapper with extensions and do stuff pseudo-manually. I haven't used the SimpleCrud extension. Since you inherited the DB, hopefully it's set up well and there's a FK constraint on Distribution, Column EntryID.
In Dapper, you could set up your classes like:
using Dapper.Contrib.Extensions;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace Jacrys
{
[Table("dbo.address_book")]
public partial class AddressBook
{
[Dapper.Contrib.Extensions.Key]
public int EntryID { get; set; }
public string Last_Name { get; set; }
public string First_Name { get; set; }
public string Title { get; set; }
public string Office_Num { get; set; }
public string Cell_Num { get; set; }
public string Home_Num { get; set; }
public string Email_Address { get; set; }
public bool Special_Info { get; set; }
public bool hr24_Emails { get; set; }
public bool hr48_Emails { get; set; }
public bool RM_Emails { get; set; }
public bool Prestige_Emails { get; set; }
public bool GEB_Emails { get; set; }
public bool LAW_Emails { get; set; }
//use this only if you need all of the distributions to be
//part of your main AddressBook class
public IEnumerable<Distribution> Distributions { get; set; }
public static AddressBook GetById(short id)
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.Get<AddressBook>(id);
}
}
public static IEnumerable<AddressBook> GetAll()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.GetAll<AddressBook>();
}
}
public int Insert()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return (int)cn.Insert(this);
}
}
public bool Update()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.Update(this);
}
}
public bool Delete()
{
using (IDbConnection cn = new SqlConnection("getConnString"))
{
cn.Open();
return cn.Delete(this);
}
}
}
[Table("dbo.distribution")]
public partial class Distribution
{
[Dapper.Contrib.Extensions.Key]
public int Key { get; set; }
public int EntryID { get; set; }
public string Brand { get; set; }
public string Location_Mnemonic { get; set; }
public int Location_Code_Numeric { get; set; }
public string Division_Mnemonic { get; set; }
public string Region_Mnemonic { get; set; }
public string Zone_Mnemonic { get; set; }
public string District_Mnemonic { get; set; }
//similar CRUD methods to AddressBook follow here
}
}
Then with a GridView like:
<asp:GridView ID="gvAddresses" runat="server" AutoGenerateColumns="true" DataKeyNames="EntryID">
</asp:GridView>
You can load it up in the code behind with (and adding lambda expression for pre-sorting):
gvAddresses.DataSource = Jacrys.AddressBook.GetAll().OrderBy(c=>c.Last_Name);
Any dropdowns you need can be loaded in similar ways.
Everything depends on your needs. If you have a gridview of Distribution, then you can add in a dropdown for Address when in edit mode (in the row data bound event). When you go to update and save, you'll have to find the control in the row and parse it's selected value before saving the record. There really isn't a nifty one single way to get this done. Though, if you have all of your business classes set up with CRUD methods you can wire it all together more simply.

EF Code first join based on a range

I am using EF v6 Code First against an existing SQL DB (so the schema is fairly fixed).
I need to build a model for the following classes and wanted to know if there is a was a way to map a relationship between a Reading and a TemperatureCategory where the Reading's temperature falls between the lower and upper bounds of the TemperatureCategory?
public class Reading
{
public int Id { get; set; }
...
public double Temperature { get; set; }
...
public virtual TemperatureCategory Category { get; set; }
}
public class TemperatureCategory
{
public int Id { get; set; }
public string Description { get; set; }
public double LowerBound { get; set; }
public double UpperBound { get; set; }
...
}
Many thanks
It's an interesting idea, but no, you can't. Joins are always based on equality.
So you have to query the TemperatureCategory. For instance
from r in context.Readings
let category = context.TemperatureCategories
.FirstOrDefault(c => c.LowerBound < r.Temperature
&& c.UpperBound >= r.Temperature)
select new { Reading = r, Category = category.Description }

Asp.net MVC 4 Code First Return Specific Fields from Navigation Property

Been stuck on this for a while so i thought i would ask. I am sure there is something simple i am missing here. Trying to learn Asp.net mvc 4 on my own by building a simple app.
Here is the model:
public class Category
{
public int Id { get; set; }
[Required]
[StringLength(32)]
public string Name { get; set; }
//public virtual ICollection<Note> Notes { get; set; }
private ICollection<Note> notes;
public ICollection<Note> Notes
{
get
{
return this.notes ?? (this.notes = new List<Note>());
}
}
}
public class Note
{
public int Id { get; set; }
[Required]
public string Content { get; set; }
[Required]
[StringLength(128)]
public string Topic { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
public virtual IEnumerable<Comment> Comments { get; set; }
public virtual ICollection<Tag> Tags {get; set;}
public Note()
{
Tags = new HashSet<Tag>();
}
}
public class Tag
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Note> Notes { get; set; }
public Tag()
{
Notes = new HashSet<Note>();
}
}
I call this method in a repository from the controller:
public IQueryable<Note> GetAll()
{
var query = _db.Notes.Include(x => x.Category).Include(y => y.Tags);
return query;
}
On the home controller i am trying to return a list of all the notes and wanted to include the category name that it belongs to as well as the tags that go with the note. At first the did not show up so i read some tutorials about eager loading and figured out how to get them to show.
However, my method is not that efficient. The mini-profiler is barking at me for duplicate queries because the navigation properties for category and tags are sending queries for the notes again. IS there any way to just return the properties i need for the category and tag objects?
I have tried several methods with no luck. I was hoping i could do something like this:
var query = _db.Notes.Include(x => x.Category.Name).Include(y => y.Tags.Name);
But i get an error: Cannot convert lambda expression to type 'string' because it is not a delegate type
I have seen that error before that was caused by some missing using statements so i already double checked that.
Any suggestions? Thanks for the help