using foreign keys with MudDataGrid - mudblazor

I have the following object:
`
public class Permissions : Item
{
public int Id { get; set; }
public AppUser User { get; set; }
public Component Component { get; set; }
public string Permission { get; set; }
}
`
My MudDataGrid:
`
<MudDataGrid T="Permissions" Items="#permissions" ReadOnly="#_readOnly" EditMode="#(_isCellEditMode ? DataGridEditMode.Cell : DataGridEditMode.Form)"
StartedEditingItem="#StartedEditingItem" CancelledEditingItem="#CancelledEditingItem" CommittedItemChanges="#CommittedItemChanges"
Bordered="true" Dense="true" EditTrigger="#(_editTriggerRowClick ? DataGridEditTrigger.OnRowClick : DataGridEditTrigger.Manual)">
<Columns>
<Column T="Permissions" Field="User" Title="UserName" IsEditable="false" />
<Column T="Permissions" Field="**Component.ComponentName**" IsEditable="false" />
<Column T="Permissions" Field="Permission" />
<Column T="Permissions" Hidden="#(_isCellEditMode || _readOnly || _editTriggerRowClick)" CellClass="d-flex justify-end">
<CellTemplate>
<MudIconButton Size="#Size.Small" Icon="#Icons.Outlined.Edit" OnClick="#context.Actions.StartEditingItem" />
</CellTemplate>
</Column>
</Columns>
`
both 'AppUser' and 'Component' are foreign keys to other objects. Data is returned fine, however I am having dificulty displaying these objects on the experimental MudDataGrid.
I know that the MudDataGrid isn't 'live' currently, but I'm only using it on a test system at present. Is anyone aware of a way for me to reference the items of the foreign object in the grid? I thought it would be something like 'Field="Component.ComponentName', but I get a nullreferenceexception.
I've tried 'Field="Component.ComponentName"' ,'Field="Component[ComponentName]"' to no avail.

Related

Ant design blazor validation on child components not displaying validation message

I am using Ant design Blazor and trying to create a child component and apply validation as usual from the parent component. Below is my code.
Child component
<AntDesign.FormItem Label="#Label">
<AntDesign.InputNumber Step="Step" Min="Min" #bind-Value="#Amount" OnChange="OnAmountChanged"
TValue="double?" />
</AntDesign.FormItem>
#code {
[Parameter]
public string Label { get; set; }
[Parameter]
public double Step { get; set; }
[Parameter]
public double Min { get; set; } = double.MinValue;
[Parameter]
public double Max { get; set; } = double.MaxValue;
[Parameter]
public string Placeholder { get; set; }
[Parameter]
public double? Amount { get; set; }
[Parameter]
public EventCallback<double?> AmountChanged { get; set; }
private async Task OnAmountChanged(double? value)
{
await AmountChanged.InvokeAsync(value);
}
}
Parent component
<AntDesign.Content>
<AntDesign.Form LabelColSpan="8"
WrapperColSpan="16"
Model="#exchangeRate"
OnFinish="#OnFinish"
OnFinishFailed="#OnFinishFailed">
<Validator>
<FluentValidator TValidator="ExchangeRateValidator" />
</Validator>
<ChildContent>
<AntDesign.FormItem Label="Rate">
<AntDesign.InputNumber Step="0.1" Min="0" #bind-Value="context.Rate" Formatter="RateFormat" />
</AntDesign.FormItem>
<FormItem Label="Date">
<DatePicker TValue="DateTime?" Format="yyyy/MM/dd" #bind-Value="context.Date">
</DatePicker>
</FormItem>
<InputNumberComponent Label="Rate" #bind-Amount="context.Amount"></InputNumberComponent>
<Button Type="primary" HtmlType="submit">Submit</Button>
</ChildContent>
</AntDesign.Form>
</AntDesign.Content>
As can be seen, I am binding the value of Amount to the component directly using #bind-Amount. But, when I click on the Submit button, it triggers validation and displays the validation messages on the first two fields but not on the child component.
Any pointers?
A colleague of mine was able to help with the answer. We had to look into the Ant Design Blazor source for the FormItem to figure out what is happening and get the answer. To get the validation messages, Ant is depending on the validation messages in the EditContext but retrieving them using the Any input control's FieldIdentifier.
The FieldIdentifier is created by Ant using the ValueExpression of the control and not the value. When we set the value, from the child control, the Value taken as the ValueExpression and in turn, when looking for validation messages, it searches for error messages against Value and not the actual model field.
Setting the ValueExpression to a binding expression when binding to the child property fixed the issue.

Missing inverse property in asp.net webapi odata $metadata

have very simple relationship between two entities and I am trying to expose them with asp.net webapi odata controllers but it seems that something is wrong with $metadata.
When I run jaydatasvcutil.exe on the $metadata I get warning: inverseProperty other side missing.
When I use breezejs loadNavigationProperty I get similar error.
I have the problem even with official example.
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations
You can observe the $metadata here http://sdrv.ms/Z5Klfw
Please help.
When we are generating navigation properties we don't reuse the relationships.
For example, lets say you have simple model,
public class Product
{
public int Id { get; set; }
public Supplier Supplier { get; set; }
}
public class Supplier
{
public int Id { get; set; }
public Product[] Products { get; set; }
}
The $metadata for the navigation properties that we generate looks like this,
<NavigationProperty Name="Supplier" Relationship="ProductsService.Models.ProductsService_Models_Product_Supplier_ProductsService_Models_Supplier_SupplierPartner" ToRole="Supplier" FromRole="SupplierPartner" />
<NavigationProperty Name="Products" Relationship="ProductsService.Models.ProductsService_Models_Supplier_Products_ProductsService_Models_Product_ProductsPartner" ToRole="Products" FromRole="ProductsPartner" />
Notice that we are generating two relationships instead of one. The reason we do that is that it is a hard problem to figure out if two navigation properties represent the same relationship. Take the instance of Product and Manufacturer.
public class Manufacturer
{
public int Id { get; set; }
public Product[] RawMaterials { get; set; }
public Product[] Produces { get; set; }
}
public class Product
{
public int Id { get; set; }
public Manufacturer[] Producers { get; set; }
public Manufacturer[] Consumers { get; set; }
}
It is not trivial to figure out that Maufacturer.RawMaterials and Product.Consumers should share the same relationship and Manufaturer.Produces and Product.Producers should share the same relationship. We chose not to do it because the clients that we know of don't make much out of this information.
All this happens because OData uses the same EDM model as the entityframework. Entityframework requires this information as it maps these relationships to association sets which would become tables in the database.
Another reason we chose not to do it is that this could be going away in OData V4. Check out the working draft here (page 23 and page 57 would be of interest). In short, navigation properties in $metadata in OData V4 would look more like this,
<NavigationProperty Name="Category" Type="Self.Category" Nullable="false" Partner="Products" />
Notice that there is no relationship and there would be no association sets.

Deserializer the respond stream from web failed

I need to convert my web application to phone application. I was succeed to deserializer the request respond into the generic list on my web app, but I haven't figure out how to do it on the phone app. On the web I can use DataContractSerializer and XmlDictionaryRead.CreateTextReader and System.Xml.XmlDictionaryReaderQuotas(), but there is no such method on Windows phone. I modified the code and get the error like that
Error in line 1 position 2. Expecting element 'ArrayOfQueueItem' from namespace 'http://schemas.datacontract.org/2004/07/CMSPhoneApp.DataObjects'..
//Encountered 'Element' with name 'QueueItem', namespace ''.
There is the code to deserialzier
try{
using (XmlReader r = XmlReader.Create(new StringReader(content)))
{
var ser = new DataContractSerializer(typeof(T));
var reader = XmlDictionaryReader.CreateDictionaryReader(r);
ser = new DataContractSerializer(typeof(T));
var deserializedItem = (T)ser.ReadObject(reader, true);
reader.Close();
return deserializedItem;
}
}
I read the respond stream into the string as below:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfQueueItem xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DataObjects">
<QueueItem>
<callNumber>349551</callNumber>
<errorMsg
i:nil="true" />
<link>/Call/349551</link>
<page>Call</page>
<siteCity>Burnaby</siteCity>
<status>Open</status>
<summary>Mobile Application Research</summary>
</QueueItem>
<QueueItem>
<callNumber>376209</callNumber>
<errorMsg
i:nil="true" />
<link>/Call/376209</link>
<page>Call</page>
<siteCity>Burnaby</siteCity>
<status>Open</status>
<summary>July 2012 ASD Calls of the Month.</summary>
</QueueItem>
</ArrayOfQueueItem>
The following is the "QueueItem" class:
namespace CMSPhoneApp.DataObjects
{
//This is Model
public class QueueItem
{
public string callNumber { get; set; }
public string summary { get; set; }
public string status { get; set; } //queInvoiceAdmin no status
public string link { get; set; }
public string errorMsg { get; set; }
public string page { get; set; }
public string siteCity { get; set; }
}
}
Even I trid to cut the respond stream into as follows, I stil got the same error:
<QueueItem>
<callNumber>349551</callNumber>
<errorMsg
i:nil="true" />
<link>/Call/349551</link>
<page>Call</page>
<siteCity>Burnaby</siteCity>
<status>Open</status>
<summary>Mobile Application Research</summary>
</QueueItem>
<QueueItem>
<callNumber>376209</callNumber>
<errorMsg
i:nil="true" />
<link>/Call/376209</link>
<page>Call</page>
<siteCity>Burnaby</siteCity>
<status>Open</status>
<summary>July 2012 ASD Calls of the Month.</summary>
</QueueItem>
Would someone guide me or show me the example or link to solve this problem. Thanks in advance.
It may not be a good solution, but it fix my issue. I changed the 'schemas.datacontract.org/2004/07/DataObjects' to 'schemas.datacontract.org/2004/07/CMSPhoneApp.DataObjects'. Therefore it can find the class location. Also I need to create ArrayOfQueueItem Class for deserialization.

How to query Dynamic properties in NHibernate?

I have this problem.
I have a class like this:
public class WfStep
{
private readonly IDictionary properties = new Hashtable();
public virtual Guid Id { get; private set; }
public virtual string Name { get; set; }
public virtual dynamic Properties { get { return new HashtableDynamicObject(properties); } }
and its mapping file like this:
<class name="ConsoleApplication4.WfStep" table="WFSteps">
<id name="Id">
<generator class="guid"/>
</id>
<property name="Name" />
<map name="Properties" table="WFSteps_Properties" access="field.lowercase">
<key column="StepId" />
<index column="PropertyName" type="System.String"/>
<composite-element class="ConsoleApplication4.ValueItem, ConsoleApplication4">
<property name="Value" type="System.String"/>
<property name="ValueType" type="System.String"/>
</composite-element>
</map>
This example is ported from:
Ayende Support dynamic fields with NHibernate and .NET 4.0
Then I save an object to the db like this:
ie.
var step = new WfStep { Name = "John" };
var property = new ValueItem() { Value = DateTime.Now, ValueType = "System.DateTime" };
step.Properties["DateProperty"] = property ;
Session.Save(step);
Now I want to return all the WFSteps that have DateProperty set to year 2010 ie.:
var Session.Query<WfStep>().Where(x=>x.Properties.DateProperty.Year == 2010);
It throws an error:
An expression tree may not contain a dynamic operation
How can I query this type of class that has Dynamic properties.?
You can index collections mapped as a map or as list. Try the following hql
from WfStep s
where s.Properties["DateProperty"] = "2010"

nhibernate 2 linq eager load

I'm starting out with nHibernate and have a simple example that I cannot get working as I'd like.
I have two model objects (Blog and Posts) and I would like to load them all in a single query for one scenario. I want lazy loading in other cases.
I naively thought that I could write something like this:
var blogs = session.Linq<Blog>().Expand("Posts");
But this will give me an instance of blog for every post rather than adding the posts to the blog.
I know I'm doing something stupid. Can someone please point out what it is? Is it that I need to relate the post and blog entities in my linq query?
Code and Mappings:
public class Blog
{
public Blog()
{
Posts = new HashSet<Post>();
}
public virtual long Identifier { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual Post AddPost(Post post)
{
post.Blog = this;
Posts.Add(post);
return post;
}
}
public class Post
{
public virtual long Identifier { get; set; }
public virtual string Name { get; set; }
public virtual Blog Blog { get; set; }
}
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="nhibEx" namespace="nhibEx">
<class name="Blog" lazy="true">
<id name="Identifier">
<generator class="native" />
</id>
<property name="Name" not-null="true" length="100"/>
<set name="Posts" inverse="true" cascade="save-update" lazy="true">
<key column="BlogIdentifier" foreign-key="fk_Post_Blog"/>
<one-to-many class="Post"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="nhibEx" namespace="nhibEx">
<class name="Post" lazy="true">
<id name="Identifier">
<generator class="native" />
</id>
<property name="Name" not-null="true" length="255"/>
<many-to-one name="Blog" column="BlogIdentifier" class="Blog" />
</class>
</hibernate-mapping>
After searching other forums (perhaps I should of done this properly first!) I'm using this solution:
var blogs = session.Linq<Blog>();
blogs.QueryOptions.RegisterCustomAction(
criteria => criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()));
var results = blogs.Expand("Posts");
I didn't want to use Distinct as I wanted to return IQueryable
Seems to work. I just need to know the theory :)
http://nhforge.org/wikis/howtonh/get-unique-results-from-joined-queries.aspx
Distinct is what you need...
Edit:
When it doesn't work: do the distinct after the tolist.
I don't know why NHibernate loads the same number of objects as the number of database records returned and doesn't do the distinct automatically. This issue/feature is not Linq specific, but will also happen when you use criteria or hql.
session.Linq<Blog>().Expand("Posts").ToList().Distinct();
Sometimes it can be more efficient to execute 2 queries (seperate, or using multiquery/future) than executing one query with a left outer join.
We have just the same problem. It seems to me that linq is always in eager loading mode. So you don't need to do exapnd. However it is very bad. Have you tried to contact HN guys in their google group?

Resources