Unity ECS : System does not find entities - entity-component-system

I am having a problem with Unity ECS. My system does not find my entity with its query. This is my setup : I am currently testing with just one entity, that is created by a prefab, using this function :
Entity CreateEntity => GameObjectConversionUtility.ConvertGameObjectHierarchy(_parameters.carPrefab, _conversionSettings);
with
_assetStore = new BlobAssetStore();
_conversionSettings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, _assetStore);
My entity gets created properly (as i guess based on the entity window) :
My system uses this query :
Entities.ForEach((DynamicBuffer<EdgeBufferElement> pathBuffer, ref Translation position,
ref Rotation rotation, ref CarComponentData car) => {
//logic
}).Schedule(inputDeps);
But my system logic does not get executed. This is propably because the system shows that it can not find the entity :
I also tried to change the query to just reference the Translation but that lead to the same result. Do you have any idea what is going wrong here ?
Thanks for the help in advance !

This is because entities with Prefab tags are ignored in queries by default (you can easily override this ofc).
This promotes "prefab entity" pattern as calling EntityManager.Instantiate( prefab_entity ) is A LOT faster than EntityManager.Instantiate( prefab_gameObject )
using Unity.Entities;
using Unity.Jobs;
public class LetsTestQuerySystem : SystemBase
{
protected override void OnCreate ()
{
Entity prefab = EntityManager.CreateEntity( typeof(Prefab) , typeof(MyComponent) );
Entity instance = EntityManager.Instantiate( prefab );// Instantiate removes Prefab tag
EntityManager.SetName( prefab , "prefab" );
EntityManager.SetName( instance , "instance" );
}
protected override void OnUpdate ()
{
Entities
// .WithAll<Prefab>()// query prefabs only
.ForEach( ( ref MyComponent component ) => component.Value += 1 )
.WithBurst().ScheduleParallel();
}
struct MyComponent : IComponentData { public int Value; }
}

Related

Adding multiple maps when using dapper extensions

I am using dapper extensions and have a question about the class mapper. Unfortunately most of my tables need some mapping done to them such as different schemas etc.
So I find I am typically doing a lot of swapping out the DefaultMapper as per below:
public Hierarchies HierarchyGetByName(string aName)
{
Hierarchies result;
using (SqlConnection cn = GetSqlConnection())
{
cn.Open();
Type currModelMapper = DapperExtensions.DapperExtensions.DefaultMapper;
try
{
DapperExtensions.DapperExtensions.DefaultMapper = typeof(HierarchiesMapper);
IFieldPredicate predicate = Predicates.Field<Hierarchies>(f => f.Name, Operator.Eq, aName);
result = cn.GetList<Hierarchies>(predicate).FirstOrDefault();
}
finally
{
DapperExtensions.DapperExtensions.DefaultMapper = currModelMapper;
}
cn.Close();
}
return result;
}
If I access 2 tables then I have to do this twice for instance.
Is there a way to add all the mapper classes at once to say a collection and depending on the table being accessed the correct one is chosen?
You could add a set of classes within your app that apply custom remapping to your entities. For example these 3 empty classes apply the PrefixDapperTableMapper to the Profile and FileNotificationAdhocRecipient classes while the AnotherDifferentTypeOfDapperClassMapper is applied to NotificationProfile.
public class ProfileMapper : PrefixDapperTableMapper<Domain.Entities.Profile>
{
}
public class FileNotificationAdhocRecipientMapper : PrefixDapperTableMapper<Domain.Entities.FileNotificationAdhocRecipient>
{
}
public class NotificationProfileMapper : AnotherDifferentTypeOfDapperClassMapper<Domain.Entities.NotificationProfile>
{
}
and your actual mapping code exists in separate mappers (I've not shown AnotherDifferentTypeOfDapperClassMapper but that would be similar to below)
public class PrefixDapperTableMapper<T> : ClassMapper<T> where T : class
{
public PrefixDapperTableMapper()
{
AutoMap();
}
//name or schema manipulations in some overrides here.
}
As long as they're in the same assembly, DapperExtensions will find and use them or you can set the mapping assembly with code similar to:
DapperExtensions.DapperExtensions.SetMappingAssemblies({ typeof(ProfileMapper ).Assembly })

DbSet.Attach() only updates single table but not referencing ones

I have two tables: Word and Adjective, both with some properties. Primary key of both tables is ID, Adjective.ID also references Word.ID as foreign key so there is a 1-1 relationship.
I also have a repository for any kind of table with an Update function.
public void Update(T entity) {
var entry = DatabaseContext.Entry(entity);
DatabaseSet.Attach(entity);
entry.State = EntityState.Modified;
}
I take a value from the database, convert it into a ViewModel looking like this (of course it's actually a little more complex):
public class WordModel {
public int ID { get; set; }
public string OriginalWord { get; set; }
}
public class AdjectiveModel : WordModel {
public string Translation { get; set; }
}
Then I alter the values of properties Word and Translation, convert and write it back. After conversion I have an object like this:
Word = {
ID = 1
OriginalWord = y
Adjective = {
ID = 1
Translation = z
}
}
Upon updating however, only one table gets updated.
Database.Words.Update(Word) only updates the OriginalWord value in the Word table,
Database.Adjectives.Update(Word.Adjective) only updates the Translation value in the Adjective table.
When running the updates for both tables sequentially I get an InvalidOperationException: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Creating a new database entry works perfectly.
I cannot believe I have to update both tables on their own and then save the context for each. I have created the database Repository via a Tutorial that obviously didn't explain well enough what's going on with the DbSet and the DbContext, which leaves me a little helpless here.
Sadly I have no link (it is quite a while ago I created the database project)
So, what am I doing wrong here?
You entity Word contains an entity Adjective, it is then the root of the object graph. Now generally here's what you should keep in mind in the following situations :
All objects in the graph are new (new word and new adjective)
use myDbContext.Words.Add(myNewWordObjectGraph); to have the correct state you want.
Only root is new (new word and a pre-existing non modified adjective)
use myDbContext.Entry(myNewWord).state = EntityState.Added; to have the correct state you want.
Root is modified and some nodes are modified (word and adjective both exist in the DB and both have been modified)
use myDbContext.Entry(myWord).State = EntityState.Modified; and myDbContext.Entry(myAdjective).State = EntityState.Modified; to have the correct state you want. i.e. call myDbContext.Entry(myObject).State = EntityState.Modified; for each modified object in the graph whether it's the root or some other node.
Root is unchanged and/or Modified and some nodes are added, others are also unchanged and/or modified
use myDbContext.MyRootObjectDbSet.Add(myRootObject); ; this will mark all the objects in the graph as EntityState.Added including the unchanged and/or modified objects. so the next call should be for each unchanged and/or modified object in order to correct its state : myDbContext.Entry(myObject).State = ThisObjectSCorrectState;.
I Hope that helps
EDIT
Calling DbSet.Attach(...) just adds the object to the objects tracked by EF. If you modify an object before calling DbSet.Attach(...), the modifications won't be persisted to DB when you call SaveChages(), so attaching an object as is before modification, calling DbSet.Attach(...) and then modifying the object is the way to make EF aware of the modifications.
Based on the way your update method's defined I would assume your repository looks something like this maybe?
//Not threadsafe as it contains a transient object 'DbContext'.
public class Repository<T> : IRespository<T> where T : class
{
private readonly MyDbContext context;
public Repository(MtDbContext context)
{
this.context = context
}
//...
public void Update(T entity) {... }
public void Commit() { context.SaveChanges(); }
}
I would suggest changing the update method to the following :
public void Update(T entity)
{
context.Entry(entity).State = EntityState.Modified;
}
And this update method would be called for each object you updated in the graph using the same instance of the repository enclosing the DbContext.

How to Use Dependency Injection on UserControls & Forms

Running into a knowledge gap, been out of WinForms for so long, unsure if i am doing this correctly for Castle Windsor.
For the last 5 years i have developing ASP.Net applications (WebForms, MVC, etc). I now have a project where a web interface is not a viable solution, yet. So we are doing it with WinForms.
With Asp.Net, i would have just set up the Castle Windsor Container, CWC, static class and everything would have taken care of itself for Dependency Injections, etc.
I am having some issues when it comes to WinForms. I evidently cant implement the same rules for Dependency Injection that i did for the WebForms developments.
Current Implementation:
Program.cs:
static void Main () {
Initialize();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
var form = CWC.Resolve<frmMain>();
Application.Run( form );
}
public static void Initialize ( string log4netPath = null ) {
var container = new WindsorContainer();
container.Kernel.ComponentModelCreated += ( s => {
if ( s.LifestyleType == LifestyleType.Undefined )
s.LifestyleType = LifestyleType.PerWebRequest;
} );
container.Install(
new CoreManagerInstaller() ,
new DomainInstaller() ,
new RepositoryInstaller() ,
new ServiceInstaller()
);
//Installer for MVC framework -- Must be done after other installers on its own.
container.Install( new AppInstaller() );
if ( log4netPath != null ) {
//container.AddFacility( new LoggingFacility( LoggerImplementation.Log4net , log4netPath ) );
}
CWC.Init( container );
}
AppInstaller:
public class AppInstaller : IWindsorInstaller {
#region IWindsorInstaller Members
public void Install ( IWindsorContainer container , IConfigurationStore store ) {
container.Register(
Classes.FromThisAssembly()
.BasedOn<CIMForm>().LifestyleTransient() ,
Classes.FromThisAssembly()
.BasedOn<CIMTabControl>().LifestyleTransient() ,
Classes.FromThisAssembly()
.BasedOn<CIMTabPage>().LifestyleTransient() ,
Classes.FromThisAssembly()
.BasedOn<UserControl>().LifestyleTransient() );
}
#endregion
}
All the above is nothing new or problematic atm.
The problem child is the UserControl i am trying to reference Interfaces form other libraries. In WebForms i would have just dropped the Property signature and started using in the Event/Methods i needed it.
As such:
public partial class ClientInformationControl : UserControl {
public IServerRepository ServerRepository { get; set; }
private void ClientInformation_Load ( object sender , EventArgs e ) {
var servers = ServerRepository.Find().Select( s => new { Key=s.Id , Value=s.Name } );
cboServers.Items.AddRange( servers.ToArray() );
}
}
But ServerRepository never gets instantiated in this design. I have to manually call CWC.Resolve<IServerRepository>() in order for the property to have the information in need.
Is there a way to make it so that ServerRepository is automatically (auto-magically) filled with the object data from the container?
Tried doing public ClientInformationControl(IServerRepository serverRepo){} but the assignment did not persist past the constructor, so when the Control.Load event was triggered the ServerRepository Property has been emptied out.
The problem with usercontrols is that they do no get resolved by the DI framework (DIF).
You havent posted the code of your winform, but I assume the designer code looks something like this:
private void InitializeComponent()
{
this.ClientInformationControl1 = new ClientInformationControl();
[...]
}
This is because you probably dragged the user control onto the form, so the DIF does not know about it.
There are multiple ways to work around this:
1: Don't use the designer to add usercontrols, but register them and let the DIF resolve them for you. You can do this by adding them to the constuctor parameters, as property, or resolve the usercontrol whenever you need it.
2: Give the parent that is resolved (the form) a IServerRepository dependency. But then you'll have to manually wire the IServerRepository into the usercontrol tho...

Using stored procedures (Linq-to-SQL, not EF) in WCF RIA - Silverlight 4

For the love of heaven and earth I really wish someone could help me out with this issue. It seems everyone has something to say about EF but nothing about Linq-to-SQL.
I am trying to grab some data from my table via a stored procedure, believe me, that's all.
I added the Linq-to-SQL model (LAMP.dbml)
added the stored procedure (getAffectedParcel) from the server explorer. getAffectedParcel takes 2 strings as parameters
Build the application.
Added a domain service class (LAMPService)
Selected the (LAMPDataContext) as the data context class (normally I would tick generate metadata, but since I am not working with tables it's not enabled for ticking)
Added the following function to the LAMPService.cs:
public IEnumerable < getAffectedParcelResult > GetTheAffectedParcels(String v, String vf)
{
return this.DataContext.getAffectedParcel(v, vf).AsEnumerable();
}
Added the following code to a Silverlight page in an attempt to consume the stored procedure:
LAMPContext db = new LAMPContext();
try
{
var q = db.GetTheAffectedParcels("18606004005", "").Value;
foreach (getAffectedParcelResult GAP in q)
{
MessageBox.Show(GAP.Owner);
}
}
catch (Exception ex)
{
MessageBox.Show (ex.Message.ToString());
}
Build and run application. An error occurs stating:
Object reference not set to an instance of an object.
I have tried ~1000,000 ways to see if this thing would work, but to no avail. Please don't tell me to use Entity Framework, I want to use Linq-to-SQL. Can someone (anyone) help me out here.
//houdini
Calling a stored procedure from the Silverlight client happens in the Async world. Let's consider an example from the AdventureWorks database...
Here's what the Domain Service method looks like. It is calling the EF on a stored procedure in the database called 'BillOfMaterials'.
public IQueryable<BillOfMaterial> GetBillOfMaterials()
{
return this.ObjectContext.BillOfMaterials;
}
Back on the client side, here is the code for setting up the call...
public GetSp()
{
InitializeComponent();
DomainService1 ds1 = new DomainService1();
var lo = ds1.Load(ds1.GetBillOfMaterialsQuery());
lo.Completed += LoCompleted;
}
First, the Domain Service is created, and then it is used to load the results of the stored procedure. In this particular case, the result of this is an instance of 'LoadOperation'. These things are async, so the LoadOperation needs to have a callback for when it is finished. The callback code looks like this...
public ObservableCollection<BillOfMaterial> MyList { get; set; }
void LoCompleted(object sender, EventArgs e)
{
LoadOperation lo = sender as LoadOperation;
if(lo!=null)
{
MyList = new ObservableCollection<BillOfMaterial>();
foreach(BillOfMaterial bi in lo.AllEntities)
{
MyList.Add(bi);
}
dataGrid1.ItemsSource = MyList;
}
}
In this method, the 'sender' is dereferenced into the LoadOperation instance, and then all the goodies from the database can be accessed. In this trivial example, a list is built and passed to DataGrid as the ItemsSource. It's good for understanding, but you would probably do something else in practice.
That should solve your problem. :)
The best advice I can give on Silverlight and RIA is never do ANYTHING on your own until you have tried it in AdventureWorks. You will just waste your time and beat your head against the wall.
Firstly, it seems like your DomainService code is written for Invoke() rather than Query(). You should use Query as it enables you to update data back to the server.
Solution: you should add a [Query] attribute to GetTheAffectedParcels on the domain service.
[Query]
public IQueryable<Parcel>
GetTheAffectedParcels(string ParcelNumber, string LotNumber)
{
// etc.
}
Secondly, RIA Services needs to know which is the primary key on the Parcel class.
Solution: Apply a MetadataType attribute to the Parcel class, which allows you to add metadata to the Parcel class indirectly, since it is generated by Linq2Sql and you couldn't add annotations directly to the ParcelId - it'd get wiped away.
[MetadataType(typeof(ParcelMetadata)]
public partial class Parcel
{
}
public class ParcelMetadata
{
[System.ComponentModel.DataAnnotations.Key]
public int ParcelId {get; set; }
}
Thirdly, modify your client like this. Instead try this on the Silverlight client:
LAMPContext db = new LAMPContext();
try
{
var q = db.GetTheAffectedParcelsQuery("18606004005", "");
db.Load(q, (op) =>
{
if (op.HasError)
{
label1.Text = op.Error.Message;
op.MarkErrorAsHandled();
}
else
{
foreach (var parcel in op.Entities)
{
// your code here
}
}
}
}
catch (Exception ex)
{
label1.Text = op.ex.Message;
}
Much thanks to Chui and Garry who practically kicked me in the right direction :) [thanks guys...ouch]
This is the procedure I finally undertook:
-After adding the data model(LINQ2SQL) and the domain service, I created a partial class [as suggested by Chui] and included the following metadata info therein:
[MetadataTypeAttribute(typeof(getAffectedParcelResult.getAffectedParcelResultMetadata))]
public partial class getAffectedParcelResult
{
internal sealed class getAffectedParcelResultMetadata
{
[Key]
public string PENumber { get; set; }
}
}
Then, Adjusted the Domain Service to include the following:
[Query]
public IQueryable<getAffectedParcelResult> GetTheAffectedParcels(string v, string vf)
{
// IEnumerable<getAffectedParcelResult> ap = this.DataContext.getAffectedParcel(v, vf);
return this.DataContext.getAffectedParcel(v, vf).AsQueryable();
}
Then Build the app, afterwhich the getAffectedParcelResult store procedure appeared in the Data Sources panel. I wanted to access this via code however. Therefore, I accessed it in silverlight [.xaml page] via the following:
LAMPContext db = new LAMPContext();
var q = db.GetTheAffectedParcelsQuery("18606004005", "");
db.Load(q, (op) =>
{
if (op.HasError)
{
MessageBox.Show(op.Error.Message);
op.MarkErrorAsHandled();
}
else
{
foreach (getAffectedParcelResult gap in op.Entities)
{
ownerTextBlock.Text = gap.Owner.ToString();
}
}
},false);
This worked nicely. The thing is, my stored procedure returns a complex type so to speak. As of such, it was not possible to map it to any particular entity.
Oh and by the way this article helped out as well:
http://onmick.com/Home/tabid/154/articleType/ArticleView/articleId/2/Pulling-Data-from-Stored-Procedures-in-WCF-RIA-Services-for-Silverlight.aspx

Linq to Sql - How to update an object using a repository pattern?

There is tons of information on this, but even after reading for hours and hours I can't seem to get this to work the way I want.
I'm trying to update a User object by passing in a User object and generically comparing changes to a User object I pull out of the database. I always end up getting the NotSupportedException when using this method:
An attempt has been made to Attach or
Add an entity that is not new, perhaps
having been loaded from another
DataContext. This is not supported.
Here is how I am trying to do it:
public void SaveUser(User User)
{
using (DataContext dataContext = new DataContext(WebConfigurationManager.ConnectionStrings["database"].ConnectionString))
{
// New user
if (User.UserID == 0)
{
dataContext.Users.InsertOnSubmit(User);
}
// Existing user
else
{
User dbUser = dataContext.Users.Single(u => u.UserID.Equals(User.UserID));
Type t = dbUser.GetType();
foreach (PropertyInfo p in t.GetProperties())
{
if (p.CanWrite & p.GetValue(dbUser, null) != p.GetValue(User, null))
{
p.SetValue(dbUser, p.GetValue(User, null), null);
}
}
//dataContext.Refresh(RefreshMode.KeepCurrentValues, dbUser);
}
dataContext.SubmitChanges();
}
}
The commented out line I tried uncommented too, but it was no help.
If I comment out the foreach() loop and add a line like dbUser.UserName = "Cheese"; it will update the User's name in the database fine. That leads me to believe it is something with how the foreach() loop changing the dbUser object that causes this to fail.
When I debug the dbUser object, it appears to correctly acquire all the changes from the User object that was passed as an argument.
I also did some reading on optimistic concurrency and added a column to the table of data type timestamp, but that didn't seem to have any effect either.
What exactly am I doing wrong here?
How can I get this to generically detect what has changed and correctly persist the changes to the database?
My guess is there's a foreign key relation that you are trying to copy over that was not initially loaded (because of lazy-loading) During the copying, it's attempting to load it, but the DataContext has already been disposed.
I've been working on a similar problem. I ended up using AutoMapper to handle copying the properties for me. I have configured AutoMapper to ignore the primary key field as well as any relations. Something like:
public void Update(User user)
{
using (var db = new DataContext(...))
{
var userFromDb = db.Users.Where(x => x.Id == user.Id).Single();
AutoMapper.Mapper.Map(user, userFromDb);
db.SubmitChanges();
}
}
My automapper configuration is something like
AutoMapper.Mapper.Create<User, User>().ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.SomeRelation, opt => opt.Ignore());
You can find AutoMapper here: http://automapper.codeplex.com/
I keep my repo pretty lean, it's only job is to interact with the database. I build a Service layer on top of the repo that does a little more work
public class EventRepository : IEventRepository
{
private DBDataContext dc;
public EventRepository()
{
dc = new DBDataContext();
}
public void Create(Event #event)
{
dc.Events.InsertOnSubmit(#event);
}
public System.Linq.IQueryable<Event> Read()
{
object events = (from e in dc.Eventse);
return events.AsQueryable;
}
public void SubmitChanges()
{
dc.SubmitChanges();
}
}
Then the corresponding call from the service layer looks like this
public void AddEvent(Event #event)
{
_EventRepository.Create(#event);
}
public void SubmitChanges()
{
_EventRepository.SubmitChanges();
}
And I call it from my controller.
// AutoMapper will allow us to map the ViewModel with the DomainModel
Mapper.CreateMap<Domain.ViewModels.EventsAddViewModel, Domain.Event>();
object #event = Mapper.Map<Domain.ViewModels.EventsAddViewModel, Domain.Event>(eventToAdd);
// Add the event to the database
EventService.AddEvent(#event);
EventService.SubmitChanges();

Resources