SubSonic, SimpleRepository and entity interfaces - subsonic

Firstly, I want to apologize for my English, not my strongest side.
To the question. In my current project, I have interfaces to my entities so I can use Subsonic attributes at my head entites and I want to be able to seamlessly switch O/R mapper in the future.
Anyway, I get an error when I try to use my interfaces and SimpleRepositorys classes like Single<>, All<> and so on.
I know why I get the error message but I need help to find a way to get around it.
Error message:
System.InvalidCastException: Unable to cast object of type 'SubSonic.DomainObjects.User' to type 'Core.DomainObjects.IUser'.
Code:
public IUser FindById(int id) {
var user = _repository.Single<User>(x => x.Id == id);
return (IUser)user;
}
As you can see I have tried to make User to IUser order to work when I want to add data, but without success. What can I do to make this work?
Thank you,
Timmie

I don't think subsonic is the problem in this situation. This code will work:
namespace Core.Objects
{
public interface ICustomer
{
int CustomerID { get; set; }
string Name { get; set; }
}
}
Code for the actual class:
namespace Business.Entities
{
public class Customer: Core.Objects.ICustomer
{
public int CustomerID { get; set; }
[SubSonicStringLength(50)]
public string Name { get; set; }
}
}
And finally, the function to get the customer:
private static ICustomer CustomerByID(int id)
{
var repos = new SimpleRepository("Test", SimpleRepositoryOptions.None);
var customer = repos.Single<Customer>(c => c.CustomerID == id);
return (ICustomer) customer;
}

Related

Map properties by nameing convention

I am using automapper to map some objects between the database and another representation.
The entity looks something like
public class MyEntity {
public int Id { get; set; }
public Guid RowId { get; set; }
}
public class MyObject {
public Guid Id { get; set; }
}
As you can see, the names and types are unaligned.
Since I got many Entities and Objects, I'd rather not CreateMap<A, B>().ForMember(d => d.Id, mex => mex.MapFrom(s => s.RowId));.
To not having to do the above Convention:
AddMemberConfiguration()
.AddMember<NameSplitMember>()
.AddName<ReplaceName>(_ => _.AddReplace("RowId", "Id"));
This does not what I suspected it to do and I was not able to figure out, how to use the ReplaceName Convention.
So I'd like to hear ideas about how to map that types.
MyEntity and MyObject both are base types, so I could also use that.
What I'm trying to archieve in pseudo-code:
if(source is MyEntity && target is MyObject)
{
target.Id = source.RowId;
}
ForAllMembers
On recommendation of #lucian-bargaoanu I tried looking into ForAllMembers.
I did the following in the MapperProfile:
public class MapperProfile : Profile {
public MapperProfile() {
ForAllMaps(MapEntityBaseId);
}
protected void MapEntityBaseId(TypeMap map, IMappingExpression mex)
{
if (!map.SourceType.IsSubclassOf(typeof(EntityBase)))
return;
if (!map.DestinationType.IsSubclassOf(typeof(MyObject)))
return;
mex.ForMember("Id", opt => opt.MapFrom("RowId"));
}
}
also the debugger hints me, that ForAllMember is executed as expected, it still fails the mapping.
I created a GIST for the ForAllMembers: https://gist.github.com/anonymous/511a1b69b795aa2bc7e7cd261fcb98b1

Abstract Azure IMobileServiceTable<T> behind repository

I want my repsository to be independent of the data access technology. Currently I am working on a Xamrin.Forms App that uses Azure Mobile App Services for data access. For performance and flexibility reasons I want my repository to look simmilar like the following:
Task<IEnumerable<IDomainObject>> GetDomainObjectAsync(Func<IQueryable<IDomainObject>, IQueryable<IDomainObject>> query)
Suppose my IDomainObject looks like the following:
public interface IDomainObject
{
string Name { get; }
}
and my DataAccess Object:
internal class AzureDomainObject : IDomainObject
{
public string Name { get; set; }
public string Id { get; set; }
}
As far as I found out and tested I can do the following to query the database within my repository implementation:
public async Task<IEnumerable<IDomainObject>> GetDomainObjectAsync(Func<IQueryable<IDomainObject>, IQueryable<IDomainObject>> query)
{
// _table of type IMobileServiceTable<AzureDomainObject> gotten by MobileServiceClient
var tableQuery = _table.GetQuery();
tableQuery.Query = tableQuery.Query.Take(4); // 1) this was for testing and it works (ordering etc also works)
// tableQuery.Query = query(tableQuery.Query); // 2) this was my initial idea how to use the input param
await _table.ReadAsync(tableQuery);
}
My poblem now is how to use the input param query to replace 1) with 2).
tableQuery.Query expects an IQueryable<AzureDomainObject> but query is of type IQueryable<IDomainObject>.
Neither .Cast<AzureDomainObject>() nor .OfType<AzureDomainObject>() work to convert. Nor does (IQueryable<IAzureDomainObject>)query; work.
Cast and OfType throw NotSupportedException and the hard cast throws an InvalidCastException.
I also tried to extract the Expression from the query input param and assign it to the tableQuery.Query. But then a runtime exception occurs that they are not compatible.
Another idea I had was to use the ReadAsync(string) overload and pass the string representation of the passed query param. But this way I don't know how to generate the string.
So the final question is: Does anyone knows how to hide both AzureDomainObject and IMobileServiceTable from the domain model but keep the flexibility and performance benefits of IQueryable in the repository interface?
According to your description, I checked this issue and here is my implementation for this scenario, you could refer to them.
Model:
public class TodoItem : IDomainObject
{
public string Id { get; set; }
[JsonProperty(PropertyName = "text")]
public string Text { get; set; }
[JsonProperty(PropertyName = "complete")]
public bool Complete { get; set; }
}
public interface IDomainObject
{
string Id { get; set; }
}
Repository:
public interface IAzureCloudTableRepository<T> where T : IDomainObject
{
Task<IEnumerable<T>> GetDomainObjectAsync(Func<IQueryable<T>, IQueryable<T>> query);
}
public class AzureCloudTableRepository<T> : IAzureCloudTableRepository<T> where T : IDomainObject
{
IMobileServiceTable<T> table;
public AzureCloudTableRepository(MobileServiceClient client)
{
this.table = client.GetTable<T>();
}
public async Task<T> CreateItemAsync(T item)
{
await table.InsertAsync(item);
return item;
}
public async Task<IEnumerable<T>> GetDomainObjectAsync(Func<IQueryable<T>, IQueryable<T>> query)
{
var tableQuery = this.table.CreateQuery();
tableQuery.Query = tableQuery.Query.Take(4); //the internal fixed query
tableQuery.Query = query(tableQuery.Query); //the external query
return await tableQuery.ToEnumerableAsync();
}
}
TEST:
var mobileService = new MobileServiceClient("https://{your-app-name}.azurewebsites.net");
var todoitem = new AzureCloudTableRepository<TodoItem>(mobileService);
var items = await todoitem.GetDomainObjectAsync((query) =>
{
return query.Where(q => q.Text!=null);
});

C# ConcurrentDictonary Setting values in collection other then the key

Please look through my code before closing it this time.
The code below works but seems very hacked, I am looking for suggestions on to achieve the same thing with cleaner code or is this as good as it gets.
The code calling the Add and Remove will be from different threads that could possible access the code at the same time, so it must remain thread-safe.
using System;
using System.Collections.Concurrent;
namespace Server
{
public class Company
{
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public ConcurrentDictionary<string, Employee> Employees = new ConcurrentDictionary<string, Employee>();
}
public class Employee
{
public string First { get; set; }
public string Last { get; set; }
public string Ext { get; set; }
}
public class Clients
{
public ConcurrentDictionary<string, Company> CompaniesDict = new ConcurrentDictionary<string, Company>();
public bool Add_Company(string ID, string Name, string Address, string Phone) //This function works
{
Company MyCompany = new Company();
Employee MyEmployees = new Employee();
MyCompany.Name = Name;
MyCompany.Address = Address;
MyCompany.Phone = Phone;
MyCompany.Employees = MyEmployees;
return CompaniesDict.TryAdd(ID, MyCompany);
}
public bool Remove_Company(string ID) //This function works
{
return CompaniesDict.TryRemove(ID, Company tCompany);
}
//This is were I need the help this seems so hacked. Im not trying to update the key, but the value intstead
public bool Set_CompanyName(string ID, string Name)
{
CompaniesDict.TryGetValue(ID, out Company oCompany);
Company nCompany;
nCompany = oCompany;
nCompany.Name = Name;
return CompaniesDict.TryUpdate(ID, nCompany, oCompany);
}
public string Get_CompanyName(string ID)
{
CompaniesDict.TryGetValue(ID, out Company tCompany);
return tCompany.Name;
}
}
}
Please don't just close this and link me to some useless code you call a duplicate. Sorry to be so blunt but this has recently happened to me by a fellow coder on this site. If you have questions that I can answer so that you can full help me please ask them.
Thanks for you help in advance.
There is a much easier approach, as you are updating a field on an object.
Please note that I don't have C# installed on my current PC, so can't validate this.
Note that I declare the out parameter, but don't construct a new one that would be destroyed immediately and I modify the object itself.
i.e.
Company company;
not
Company company=new Company();
This will still not be deterministic if multiple threads call SetCompanyName(), as the new name is updated on the live object and there could be a potential race condition. However the Add and Remove will be, even if Remove removes the company instance just before its name is updated.
public bool Set_CompanyName(string ID, string Name)
{
Company company;
var retval= CompaniesDict.TryGetValue(ID, out company)
if (retval) {
company.Name=Name; // Update your company object directly
}
//else Do something such as throw an exception if it's not found
return retval;
}

I'm sorry, but it's another: Found shared references to a collection

Recently I've been adding some features to my local project, and I'm struggling with this one part. The short of it is NHibernate give me the line:
Found shared references to a collection: Page.Menus
The simple part of it is, I only want to save the relational map that binds menus to pages, which you can see the Reference below in PageMap. I should add that loading data works great, it's the saving that's killing me.
I spent a lot of time yesterday digging through here, and the good ole web, trying to find the answer, and I just kept striking out. Maybe it's bad searching on my part, but I feel I tried everything. If you know where it is can you please supply it? (thanks)
For the actual details, I've tried to simplify what's going on. I've added the PageReposity, UnitOfWork, and the proxy objects, as well as their mappings.
Where I get hazy on is the cascade, and how to save the relationship table (many to many)
For the first part, here is what happens when I save (Add). I've actually done this a few ways within the PageRepository. Since I'm strugging with the Add(), I've included it here:
public override bool Add(Page entity)
{
UnitOfWork.Save(entity);
/* I have also tried doing the following below, which doesn't help
for (var index = 0; index < entity.Menus.Count; index++)
{
UnitOfWork.Save(entity.Menus[index]);
}
*/
UnitOfWork.Commit(); // bam, error!
return true;
}
In the UnitOfWork I've setup the following in the ctor (the ISession is injected each time via ninject like so:
// DomainModule
...
Bind<ISFactory>().To<NHibernateSessionFactory>()
.InSingletonScope()
.WithConstructorArgument("connectionString", _connectWeb);
...
// Back to the UnitOfWork
...
private ISession Session { get; set; }
...
public UnitOfWork(ISFactory sessionFactory)
{
_sessionFactory = sessionFactory.GetSessionFactory();
Session = _sessionFactory.OpenSession();
Session.FlushMode = FlushMode.Never; // I have also tried FlushMode.Commit
_transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
}
...
public void Save(object obj)
{
Session.Save(obj);
}
...
public void Commit()
{
if (!_transaction.IsActive)
{
throw new InvalidOperationException("Oops! We don't have an active transaction");
}
try
{
_transaction.Commit();
Session.Flush(); // I did this FlushMode.Never was set
}
catch (Exception exception)
{
_transaction.Rollback();
throw;
}
}
I've got 3 classes here:
Page, Menu, and Link.
public class Page : IEntity<int>
{
public virtual int Id { get; set; }
public virtual IList<Menu> Menus { get; set; }
}
public class Menu : IEntity<int>
{
public virtual int Id { get; set; }
public virtual IList<Link> Links { get; set; }
}
public class Link : IEntity<int>
{
public virtual int Id { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual string Url { get; set; }
}
Then I also have a Mappings:
public class PageMap : ClassMap<Page>
{
public PageMap()
{
Id(x => x.Id).GeneratedBy.Native();
HasManyToMany(x => x.Menus)
.Table("MenuToPage")
.ParentKeyColumn("FkPageId")
.ChildKeyColumn("FkMenuId").Cascade.SaveUpdate(); // the cascade is new here just trying to see if it helps
}
}
public class MenuMap : ClassMap<Menu>
{
public MenuMap()
{
Id(x => x.Id); // I had .GeneratedBy.Native(); attached here too.
HasManyToMany(x => x.Links)
.Table("MenuToLinks")
.ChildKeyColumn("FkLinksId")
.ParentKeyColumn("FkMenuId")
.OrderBy("MenuOrder ASC")
.Not.LazyLoad()
.Cascade.None(); // the cascade is new here just trying to see if it helps
}
}
public class LinkMap : ClassMap<Link>
{
public LinkMap()
{
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Url);
Map(x => x.CreatedDate);
Map(x => x.ModifiedDate);
References(x => x.MetaData, "FkMetaDataId").Not.Nullable().Not.LazyLoad();
}
}
Can anyone help me or point me in a direction, I'd really appreciate your help.
Like always thank you,
Kelly
Unfortunately you have posted everything but the construction of your objects before you safe them.
Usually this error can occur if you assign the same collection of entities to different instances. For example (pseudo code)
var menuList = new List<Menu>();...
pageA.Menus = menuList;
pageB.Menus = menuList;
This would set the reference of menuList to both, pageA.Menus and pageB.Menus.
Instead, assign all items of menuList to each page with pageA.AddRange(menuList) or a loop or whatever...

Breeze doesn't expand TPH entities correctly

Breeze doesn't expand TPH entities correctly.
When using expand in breeze if you are using TPH expand will only work for the first entity, the others properties will be null. If I change the entity not to use inheritances it works fine. I've also tested returning each entity separately in an expand query that also worked fine.
//client side code
var getResidentById = function (id, obs) {
var query = EntityQuery.from('Residents')
.where('id', '==', id)
.expand('user, currentUnit, leases, leases.unit, leases.leaseStatus');
return manager.executeQuery(query).then(function (data) {
if (obs) {
obs(data.results[0])
}
}, queryFailed);
};
//Controler Endpoint
[HttpGet]
public IQueryable<Resident>
{
return _context.Context.UserDetails.OfType<Resident>();
}
//Model
public class UserDetail : EntityBase<int>, IArchivable, IHasPhoto, IDeactivatableEntity, IUpdatable
{
public bool IsArchived { get; set; }
public int LastUpdatedById { get; set; }
public UserProfile LastUpdatedBy { get; set; }
public DateTimeOffset LastUpdatedDate { get; set; }
public string PhotoUri { get; set; }
public bool IsInactive { get; set; }
}
public abstract class UserBelongsToApartmentComplex : UserDetail, IBelongsToApartmentComplex
{
public int ApartmentComplexId { get; set; }
public virtual ApartmentComplex ApartmentComplex { get; set; }
public virtual bool IsInSameComplexAs(IRelatedToApartmentComplex otherEntity)
{
return ApartmentComplexId == otherEntity.ApartmentComplexId;
}
}
public class Staff : UserBelongsToApartmentComplex
{
public string Title { get; set; }
}
public class Admin : UserDetail
{
public string AccessLevel { get; set; }
}
public class Resident : UserBelongsToApartmentComplex
{
public string Pets { get; set; }
public bool HasInsurance { get; set; }
public virtual IList<Lease> Leases { get; set; }
public int? CurrentUnitId { get; set; }
public virtual Unit CurrentUnit { get; set; }
public Resident()
{
Leases = new List<Lease>();
}
}
//response data from sever from endpoint public IQueryable Residents()
[{"$id":"1","$type":"RadiusBlue.Core.Models.Resident, RadiusBlue.Core","Pets":"Sadie, a westie","HasInsurance":false,"Leases":[{"$id":"2","$type":"RadiusBlue.Core.Models.Lease, RadiusBlue.Core","Start":"2012-05-23T00:00:00.000","End":"2013-05-23T00:00:00.000","UnitId":2,"Unit":{"$id":"3","$type":"RadiusBlue.Core.Models.Unit, RadiusBlue.Core","Building":"B","Floor":2,"ModelName":"Tera","RentAmount":2500.00,"NumberOfBeds":1,"NumberOfBaths":3,"UnitName":"102A","IsInactive":true,"Inhabitants":[],"ApartmentComplexId":1,"ApartmentComplex":{"$id":"4","$type":"RadiusBlue.Core.Models.ApartmentComplex, RadiusBlue.Core","Name":"The Stratford","StreetAddress":"100 S Park Ave","City":"Winter Park","StateId":10,"ZipCode":"32792","PropertyManagementCompanyId":1,"IsInactive":false,"TimeZoneId":"Eastern Standard Time","TimeZone":{"$id":"5","$type":"System.TimeZoneInfo, mscorlib","Id":"Eastern Standard Time","DisplayName":"(UTC-05:00) Eastern Time (US & Canada)","StandardName":"Eastern Standard Time","DaylightName":"Eastern Daylight Time","BaseUtcOffset":"-PT5H","AdjustmentRules":[{"$id":"6","$type":"System.TimeZoneInfo+AdjustmentRule, mscorlib","DateStart":"0001-01-01T00:00:00.000","DateEnd":"2006-12-31T00:00:00.000","DaylightDelta":"PT1H","DaylightTransitionStart":{"$id":"7","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":4,"Week":1,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false},"DaylightTransitionEnd":{"$id":"8","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":10,"Week":5,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false}},{"$id":"9","$type":"System.TimeZoneInfo+AdjustmentRule, mscorlib","DateStart":"2007-01-01T00:00:00.000","DateEnd":"9999-12-31T00:00:00.000","DaylightDelta":"PT1H","DaylightTransitionStart":{"$id":"10","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":3,"Week":2,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false},"DaylightTransitionEnd":{"$id":"11","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":11,"Week":1,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false}}],"SupportsDaylightSavingTime":true},"Users":[{"$ref":"1"}],"Groups":[],"IsArchived":false,"ApartmentComplexId":1,"Id":1},"Id":2},"ResidentId":3,"Resident":{"$ref":"1"},"LeaseStatusId":4,"LeaseStatus":{"$id":"12","$type":"RadiusBlue.Core.Models.LeaseStatus, RadiusBlue.Core","Description":"Lost","Id":4},"Id":1},{"$id":"13","$type":"RadiusBlue.Core.Models.Lease, RadiusBlue.Core","Start":"2013-05-24T00:00:00.000","End":"2014-05-24T00:00:00.000","UnitId":1,"Unit":{"$id":"14","$type":"RadiusBlue.Core.Models.Unit, RadiusBlue.Core","Building":"A","Floor":2,"ModelName":"Aqua","RentAmount":2000.00,"NumberOfBeds":2,"NumberOfBaths":1,"UnitName":"101A","IsInactive":true,"Inhabitants":[{"$ref":"1"}],"ApartmentComplexId":1,"ApartmentComplex":{"$ref":"4"},"Id":1},"ResidentId":3,"Resident":{"$ref":"1"},"LeaseStatusId":1,"LeaseStatus":{"$id":"15","$type":"RadiusBlue.Core.Models.LeaseStatus, RadiusBlue.Core","Description":"Active","Id":1},"Id":2}],"CurrentUnitId":1,"CurrentUnit":{"$ref":"14"},"ApartmentComplexId":1,"ApartmentComplex":{"$ref":"4"},"Id":3,"User":{"$id":"16","$type":"RadiusBlue.Core.Models.UserProfile, RadiusBlue.Core","UserName":"vjiawon#gmail.com","FirstName":"Vishal","LastName":"Jiawon","Age":27,"PhoneNumber":"123 456 7890","IsInactive":false,"UserDetail":{"$ref":"1"},"GroupMembers":[],"MaintenanceRequests":[],"Id":3},"IsArchived":false,"LastUpdatedById":1,"LastUpdatedDate":"0001-01-01T00:00:00.000+00:00","IsInactive":false,"CreatedById":1,"CreatedDate":"0001-01-01T00:00:00.000+00:00"}]
I do not doubt that there is a bug in BreezeJS somewhere.
I can report that, at least as of v.1.3.4, Breeze can expand multiple navigation properties of a TPH class ... and not just on the first entity returned.
I just modified the "can navigate to AccountType eagerly loaded with expand" test in inheritanceTests.js in DocCode so that (a) it also expands the Status navigation and (b) the tests are performed on the 3rd entity returned rather than the 1st.
The query is something like this:
var em = newEm(); // clean, empty EntityManager
return EntityQuery.from('bankRootTPHs').take(3)
.expand('AccountType, Status'))
.using(em).execute().then(success).fail(handleFail);
...
function success(data) {
var entity = data.results[data.results.length-1]; // get the last one (the 3rd)
var type = data.query.entityType.shortName;
if (!entity) {
ok(false, "a query failed to return a single " + type);
}
// more tests
// I just set a breakpoint and inspected
// entity.accountType() and entity.status()
// Both returned the expected related entities
}
I see that both the related AccountType and the related Status are available from the entity.
So something else is wrong.
Questions about your Example
First I am compelled to observe that you have a lot of expands. I count 5 related entities. That can hurt performance. I know we're not talking about that but I'm calling it out.
Second, the super class UserDetail is concrete but the intermediate derived class UserBelongsToApartmentComplex is abstract. You have inheritance class hierarchies that go concrete/abstract/concrete. The queried type, Residents is one such class. And a class at every level maps to the "UserDetail" table, yes?
I'm pretty sure we didn't test for that scenario ... which is pretty uncommon. I wasn't even sure that worked! For now I have to take your word for it that EF allows such a construct.
It would seem that BreezeJS is confused about it. We'll take a look.

Resources