Updating and inserting in an OData service - properties

I have a Xamarin.Forms Visual Studio solution, into which I installed the “Simple.OData.Client” package with NuGet. I have the URI of an OData service and I want to load items from the table “Persons”, in which the base element type is “Person” and which contains instances of the class “Customer”, which inherits from the class “Person”, as I can see when opening the URI to which I append “/$metadata”.
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="A">
...
<EntityType Name="Person" Abstract="true">
...
<EntityType Name="Customer" BaseType="A.Person">
...
<EntityContainer Name="Model" m:IsDefaultEntityContainer="true">
...
<EntitySet Name="Persons" EntityType="A.Person"/>
...
I create an instance of the service:
ODataClient clientSimple = new ODataClient("http://.../.../odata.v3/default");
I load items from the data table:
System.Collections.Generic.IEnumerable<System.Collections.Generic.IDictionary<string, object>> persons = await clientSimple.For("Persons").FindEntriesAsync();
The items are returned as dictionaries where the keys are the property names and the values are the property values. I see that the properties from the “Person” entity type as well as those added in the derived “Customer” type are present.
I know that there is also a possibility of the typed syntax:
var personsTyped = await clientSimple.For<Person>().FindEntriesAsync();
However, I do not know where to get the definition of the “Person” class so that I can use it here as the generic type parameter.
Then I want to modify an entry in the OData service:
await clientSimple.For("Persons").Key(1).Set(new { FirstName = "Johnny" }).UpdateEntryAsync();
This works as long as I only update a property defined in the “Person” entity type, but trying to modify a property added in the “Customer” entity type raises an exception:
await clientSimple.For("Persons").Key(1).Set(new { FirstName = "Johnny", SalesPerson = "..." }).UpdateEntryAsync();
[Simple.OData.Client.UnresolvableObjectException] No property or association found for [SalesPerson].
Trying to insert a new item also fails:
var newObjectCreated = await clientSimple.For("Persons").Set(new { FirstName = "...", ... }).InsertEntryAsync();
[Simple.OData.Client.WebRequestException] Internal Server Error
How can I solve this so that I can update all properties and insert new items?

There are several source of information that might be useful for you. First, I suggest you have a look at Simple.OData.Client wiki pages, in particulary pages that give examples of how to modify data:
https://github.com/object/Simple.OData.Client/wiki/Modifying-data
Then there are plenty of examples that you can get from the project tests, look here for example:
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/InsertTests.cs
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/InsertTypedTests.cs
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/UpdateTests.cs
https://github.com/object/Simple.OData.Client/blob/master/Simple.OData.Client.Tests.Net40/UpdateTypedTests.cs
And if you want to use typed syntax (which I recommend) you should define your entity types yourself, currently Simple.OData.Client doesn't have any entity type generation utility.

Related

Sulu: Entity has no field or association error

I'm following Sulu example here: https://github.com/sulu/sulu-workshop/
trying to set translations for custom entity type.
My entity file has getter for field "home_team" defined like:
/**
* #Serializer\VirtualProperty(name="home_team")
*/
public function getHomeTeam(): ?string
{
$translation = $this->getTranslation($this->locale);
if (!$translation) {
return null;
}
return $translation->getHomeTeam();
}
So field is not actually part of that entity, but of it's translation entity since it suppose to be translatable.
When I try to create new object of that entity type it works well. I can see in database that field values are stored well and I don't get any error.
But on overview page instead of list of all objects I get error:
[Semantical Error] line 0, col 73 near 'home_team AS': Error: Class App\Entity\MatchEvent has no field or association named home_team
Any idea what could be wrong here?
If you wanna see the translation in the listView you have to create a real translationEntity, like in the workshop project. In this post it is already explained, how to translate a custom entity correctly.
If you have already created your translationEntity you have to configure the relation of the translation to your main entity via a join. Here is an example in the workshop for this configuration.
Sulu uses optimised queries to create the list-object directly from the database. So the entity itself does not get hydrated or serialised for performance reasons. Thus your virtualProperty is never executed.

RepoDb cannot find mapping configuration

I'm trying to use RepoDb to query the contents of a table (in an existing Sql Server database), but all my attempts result in an InvalidOperationException (There are no 'contructor parameter' and/or 'property member' bindings found between the resultset of the data reader and the type 'MyType').
The query I'm using looks like the following:
public Task<ICollection<MyType>> GetAllAsync()
{
var result = new List<MyType>();
using (var db = new SqlConnection(connectionString).EnsureOpen())
{
result = (await db.ExecuteQueryAsync<MyType>("select * from mytype")).ToList();
}
return result;
}
I'm trying to run this via a unit test, similar to the following:
[Test]
public async Task MyTypeFetcher_returns_all()
{
SqlServerBootstrap.Initialize();
var sut = new MyTypeFetcher("connection string");
var actual = await sut.GetAllAsync();
Assert.IsNotNull(actual);
}
The Entity I'm trying to map to matches the database table (i.e. class name and table name are the same, property names and table column names also match).
I've also tried:
putting annotations on the class I am trying to map to (both at the class level and the property level)
using the ClassMapper to map the class to the db table
using the FluentMapper to map the entire class (i.e. entity-table, all columns, identity, primary)
putting all mappings into a static class which holds all mapping and configuration and calling that in the test
providing mapping information directly in the test via both ClassMapper and FluentMapper
From the error message it seems like RepoDb cannot find the mappings I'm providing. Unfortunately I have no idea how to go about fixing this. I've been through the documentation and the sample tutorials, but I haven't been able to find anything of use. Most of them don't seem to need any mapping configuration (similar to what you would expect when using Dapper). What am I missing, and how can I fix this?

How to display only specific columns of a table in entity framework?

how to display the some specific columns of table instead of whole table in entity framework.
using (DataEntities cxt = new DataEntities())
{
notes note = cxt.notes.Where(no => no.id == accID).SingleOrDefault();
return notes;
}
For this purpose, I would suggest you to make use of ViewModel like following :-
notes note = cxt.notes.SingleOrDefault(no => no.id == accID);
var model = new YourViewModel // Your viewModel class
{
ID = note.ID,
PropertyOne = note.PropertyOne, // your ViewModel Property
PropertyTwo = note.PropertyTwo
};
You can do this with QueryView.
This implies editing your model directly in XML as there is no designer support for this, but you will get an independant entity with less fields than the original one.
Advantages:
You can then query data base for this truncated entity directly (you will get only fields you need from the data base - no need to get whole entity from DB and trancate it in code)
It is good in scenarios where you want to send this truncated entity to the
client
with WCF to minimize traffic (e.g. when building big lists on client
that basically need only name and ID and no other entity specific
information).
Disadvantages:
This QueryView-based entity is read only. To make it writeable you will have to add r/w functionality yourself

NHibernate dynamic mapping

I am looking for some way to dynamically map database tables classes in my application using nhibernate (or if some other ORM works then let me know). I am fairly new to nhibernate, I used entity frameworks in the past though.
Most of my application will be using a static structures and fluent nhibernate to map them.
However there are multiple database tables that will be needed to be created and mapped to objects at each install site. These will all have as a base structure (id,name etc) however they will have additional fields depending on the type of data they are capturing. From some reading I found that I can use the "dynamic-component" mapping in xml to add fields using an IDictionary Attributes property. This is the first step and seems relatively straight forward. Ref (http://ayende.com/blog/3942/nhibernate-mapping-dynamic-component)
The second step is where I am struggling. I will need to define tables and map them depending on the client’s need. As stated above each of the tables will have a set of static properties, and some dynamic ones. They will also need to reference a static “Location”Class as shown below
Location (STATIC) (id,coordinates)
-----DynamicTable1 (DYNAMIC) (id,Name,location_id, DynamicAttribute1, DynamicAttribute2........)
-----DynamicTable2 (DYNAMIC) (id,Name,location_id, DynamicAttributeA, DynamicAttributeB....)
We will need to be able to create / map as many of these DynamicTables as the client needs. DynamicTable1, DynamicTable2 etc will most likely be different in some ways for most client sites. Is there any way in nhibernate to achieve this? The creating / management of the tables in the Database will be managed elsewhere, I just need some way to get this to map in my ORM.
A bit of background
This application will be used to store geological data. As geological data is inherently different depending on where it is, and geologist are using different methods and looking for different elements (gold, coal etc), the data structure to store this information needs to be extremely flexible.
Take a look at the new Mapping By Code functionality of NH 3.2. It should make it easy to create new table definitions at runtime. In contrast to Fluent, you don't need to write a mapping class, you just can add new classes in for loops:
// lookup all dynamic tables in the database using SQL or SMO or whatever
var dynamicTables = GetDynamicTables();
// map all dynamic tables
foreach(var table in dynamicTables)
{
mapper.Class<MyGenericEntity>(ca =>
{
// use an entity name to distinguish the mappings.
ca.EntityName(table.Name);
ca.Id(x => x.Id, map =>
{
map.Column("Id");
map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
});
// map properties, using what ever is required: if's, for's ...
ca.Property(x => x.Something, map => map.Length(150));
});
}
Using the entity name you can store and load the entities to and from different tables, even if they are mapped as the same entity class. It is like Duck Typing With NHibernate..
Believe me, it won't be easy. If you are interested in a big challenge which impresses every NH expert, just go for it. If you just want to get it working you should choose a more classic way: create a static database model which is able to store dynamic data in a generic way (say: name value pairs).
see answer in Using nNHibernate with Emitted Code
class DynamicClass
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Location Location { get; set; }
public virtual IDictionary DynamicData { get; set; }
}
Template
<hibernate-mapping>
<class name="DynamicClass">
...
<dynamic-component name="DynamicData">
<!--placeholder -->
</dynamic-component>
</class>
</hibernate-mapping>
replace <!--placeholder --> with generated
<property
name="P1"
type="int" />
<property
name="P2"
type="string" />
configure Sessionfactory
var sessionFactory = new NHibernate.Cfg.Configuration()
.AddXml(generatedXml)
... // DatabaseIntegration and other mappings
.BuildSessionFactory();
Query
var query = session.CreateCriteria<DynamicClass>();
foreach (var restriction in restrictions)
{
query.Add(Restrictions.Eq(restriction.Name, restriction.Value))
}
var objects = query.List<DynamicClass>();
Edit: ups i havent realised you need multiple tables per client
Option 1:
<class name="DynamicClass" table="tablenameplaceholder"> with replace and a different Sessionfactory for each dynamic class
Option 2:
Subclassing the dynamic class and use TPS (table per subclass) mappings
Option 3: see Stefans answer just with xml
<class name="DynamicTable1" class="DynamicClass" table="DynamicTable1">

Entity Framework 4.1 Dynamically retrieve mapped column name

I am trying to construct an SQL statement dynamically.
My context is created dynamically, using reflection finding classes deriving from EntityTypeConfiguration and adding them to DbModelBuilder.Configuration.
My EntityTypeConfiguration classes specify HasColumnName to map the Entity property name to db table column name, which I need to construct my SQL statement.
namespace MyDomain {
public class TestEntityConfig : EntityTypeConfiguration<TestEntity>{
Property("Name").HasColumnName("dbName");
}
}
From What I have researched, it seems I can get access to this information through MetadataWorkspace, which I can get to through ObjectContext.
I have managed to retrieve the the entity I am interested in with MetadataWorkspace.GetItem("MyDomain.TestEntity",DataSpace.OSpace), which gives me access to Properties, but none of the properties, of Properties, give me the name of the mapped db column, as specified with HasColumnName.
Also I am not clear what DataSpace.OSpace is and why my model is constructed in this space.
If Anyone can shed some light on this I would be grateful
UPDATE
Further to #Ladislav's comments. I discovered I can get the information as follows
For the class properties
ctx.MetadataWorkspace.GetItem<ClrEntityType>("MyDomain.TestEntity", DataSpace.OSpace)).Members
For the table properties
ctx.MetadataWorkspace.GetItem<EntityType>("CodeFirstDatabaseSchema.TestEntity",SSpace).Members
So given that I only know the type MyDomain.TestEntity and Memeber "Name". How would I go about to get "dbName". Can I always assume that my mapped class will be created in CodeFirstDatabaseSchema, om order to dynamically construct the identity to retrieve it from SSpace and how would I get to the correct Member in SSpace. Can I do something like
var memIndex = ctx.MetadataWorkspace.GetItem<ClrEntityType>("MyDomain.TestEntity", DataSpace.OSpace)).Members["Name"].Index;
var dbName = ctx.MetadataWorkspace.GetItem<EntityType>("CodeFirstDatabaseSchema.TestEntity",SSpace).Members[memIndex];
MetadataWorkspace contanis several containers specified by DataSpace. Interesting for you are:
CSpace - description of conceptual model (this should contain properties)
CSSpace - mapping of conceptual model to storage model (this should contain how classes / properties are mapped to tables / columns)