I have a query where I am calculating flag and based on the flag value, I am filtering users.
Is there a way to store flag value inside query so that I dont need to call flag function twice?
[Name("AutoRepoRule")]
public class AutoRepossessionRule : BaseRule
{
public override void Define()
{
CReport cReport = default;
IEnumerable<Report> reports = default;
IEnumerable<Report> failedUser = default;
When()
.Match(() => cReport,
c => c.Product == "ABC" &&
c.reports.Any(x => GetAutoRepoFlag(x.Liabilities)))
.Let(() => failedUser, () => cReport.reports
.Where(x => GetAutoRepoFlag(x.Liabilities)));
Then()
.Do(ctx => DeclineApplication(failedUser, ref cReport,
"Rejected"))
.Do(ctx => ctx.Insert("AutoRepoRule"));
}
}
where as
protected bool GetAutoRepoFlag(List<Liability> liabilities)
{
.
.
.
}
Is there a way to store flag inside Any so that I dont need to call GetAutoRepoFlag() function twice
Related
I have multiple queries against one table. As not all columns/properties are needed I specify the columns with the help of select list. Take the following method as example. This method is working
public IEnumerable<ResultDto> GetEntityAsDto(eStatusBinderProduktion fromState, eStatusBinderProduktion toState)
{
EntityClass entityAlias = null;
ResultDto resultAlias = null;
var query = Session.QueryOver<EntityClass>(() => entityAlias)
.Where(() => entityAlias.ProduktionStatus >= (byte)fromState)
.And(() => entityAlias.ProduktionStatus <= (byte)toState);
query.SelectList(list => list
.Select(() => entityAlias.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
.Select(() => entityAlias.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
);
return query.TransformUsing(Transformers.AliasToBean<ResultDto>())
.List<ResultDto>();
}
As I need to define the SelectList in multiple methods, I tried to to move the SelectList into a separate method.
The following code is not working, NHibernate throws the exception
NHibernate.QueryException: 'could not resolve property: entity.PrimaryID of: MyProjectNamespace.DAL.Interfaces.Entities.EntityClass'
"
public IEnumerable<ResultDto> GetEntityAsDto(eStatusBinderProduktion fromState, eStatusBinderProduktion toState)
{
EntityClass entityAlias = null;
ResultDto resultAlias = null;
var query = Session.QueryOver<EntityClass>(() => entityAlias)
.Where(() => entityAlias.ProduktionStatus >= (byte)fromState)
.And(() => entityAlias.ProduktionStatus <= (byte)toState);
MapPropertiesOfEntityToResult(entityAlias, resultAlias, query);
return query.TransformUsing(Transformers.AliasToBean<ResultDto>())
.List<ResultDto>();
}
private void MapPropertiesOfEntityToResult(EntityClass entity, ResultDto resultAlias, IQueryOver<EntityClass, EntityClass> query)
{
query.SelectList(list => list
.Select(() => entity.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
.Select(() => entity.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
);
}
Additional information:
- The mappings are correct
- table is filled with test data
We do not need alias for filling SelectList. We can profit from the Type parameters coming with IQueryOver<TRoot,TSubType>:
//private void MapPropertiesOfEntityToResult(EntityClass entity
// , ResultDto resultAlias, IQueryOver<EntityClass, EntityClass> query)
private void MapPropertiesOfEntityToResult( // no need for entity
ResultDto resultAlias, IQueryOver<EntityClass, EntityClass> query)
{
query.SelectList(list => list
//.Select(() => entity.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
//.Select(() => entity.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
.Select(entity => entity.PrimaryID).WithAlias(() => resultAlias.PrimaryID)
.Select(entity => entity.SecondaryID).WithAlias(() => resultAlias.SecondaryID)
);
}
The entity is now a parameter of the passed Function and its type is coming from IQueryOver definition
I have the following controller:
public class EventsController : Controller
{
private readonly ICustomerEventRepository _customerEventRepository;
public EventsController(ICustomerEventRepository customerEventRepository)
{
_customerEventRepository = customerEventRepository;
}
public IActionResult Index(int? customerid, int? pageNumber, string code = "")
{
IQueryable<CustomerEvent> customerEvents;
if (customerid.HasValue)
{
customerEvents =
_customerEventRepository.CustomerEvents.Where(x => x.Customer.CustomerId == customerid)
.Include(x => x.Customer).OrderByDescending(x => x.CustomerEventId);
}
else if (!string.IsNullOrEmpty(code))
{
customerEvents =
_customerEventRepository.CustomerEvents.Where(x => x.EventType == code)
.Include(x => x.Customer).OrderByDescending(x => x.CustomerEventId);
}
else
{
customerEvents = _customerEventRepository.CustomerEvents
.Include(x => x.Customer).OrderByDescending(x => x.CustomerEventId);
}
var page = pageNumber ?? 1;
var onePageOfEvents = customerEvents.ToPagedList(page, 15);
return View(onePageOfEvents);
}
}
Note that
_customerEventRepository = customerEventRepository;
is my repository. It returns IQueryable form my. In the signature of the method Index I have a set of parameters. It's query parameters for filtering. Right now I have 2 (pageNumber is not filter parameter, it's for pagination), but I'm planning more. So this code is not very optimal. If I have more filter parameters I will be forced to make more and more if instructions. Because conditions don't work for LINQ. Maybe somebody had the same issue? I appreciate any help.
If I have understood you correctly, you want to build up the query based on multiple conditions.
IQueryable defers execution until the collection is materialised (for example calling ToList or iterating over the collection).
This allows you to build up the query piece by piece. See an example below.
IQueryable<CustomerEvent> customerEvents = _customerEventRepository
.CustomerEvents
.Include(x => x.Customer);
if (customerid.HasValue)
{
customerEvents = customerEvents.Where(x => x.Customer.CustomerId == customerid);
}
if (!string.IsNullOrEmpty(code))
{
customerEvents = customerEvents.Where(x => x.EventType == code);
}
// other conditions
...
// finally (this is when the query is actually executed)
var onePageOfEvents = customerEvents
.OrderByDescending(x => x.CustomerEventId)
.ToPagedList(page, 15);
return View(onePageOfEvents);
I have a lot of code like this:
Mapper.CreateMap<DbModel.Kabinetas, Kabinetas>()
.ForMember(n => n.Numeris, m => m.MapFrom(f => f.Numeris ?? ""))
.ForMember(m => m.MetaDuomenys, y => y.MapFrom(s =>
new MetaDuomenys
{
ArPanaikintas = s.SecLevel == null ? (bool?)null : s.SecLevel == 2 ? true : false,
PakeitimuData = s.PakeitimuData
}))
;
Mapper.CreateMap<DbModel.Specialybe, Specialybe>()
.ForMember(i => i.Istaigos, y => y.Ignore())
.ForMember(m => m.MetaDuomenys, y => y.MapFrom(s =>
new MetaDuomenys
{
ArPanaikintas = s.SecLevel == null ? (bool?)null : s.SecLevel == 2 ? true : false,
PakeitimuData = s.PakeitimuData
}))
;
Where the part wtih "MetaDuomenys" (a.k.a. MetaData) repeats it self over and over again..
I was hoping to be able to write something like this:
Expression<Func<BaseWMeta, MetaDuomenys>> expr = p =>
new MetaDuomenys
{
ArPanaikintas = p.SecLevel == null ? (bool?)null : p.SecLevel == 2 ? true : false,
PakeitimuData = p.PakeitimuData
};
Mapper.CreateMap<Expression<Func<BaseWMeta, MetaDuomenys>>, MetaDuomenys>();
and then use it like this:
.ForMember(m => m.MetaDuomenys, y => y.MapFrom(s => expr))
So this kinda works, when I need a single object from the database, but if I try to project it like:
db.Kabinetai.Project().To<KabinetasDC>()
I get exceptions like:
<m:internalexception>
<m:message>
The LINQ expression node type 'Lambda' is not supported in LINQ to Entities.
</m:message>
<m:type>System.NotSupportedException</m:type>
You need ProjectUsing:
Mapper.CreateMap<BaseWMeta, MetaDuomenys>()
.ProjectUsing(p =>
new MetaDuomenys
{
ArPanaikintas = p.SecLevel == null ? (bool?)null : p.SecLevel == 2 ? true : false,
PakeitimuData = p.PakeitimuData
});
ProjectUsing is like ConvertUsing (defining the mapping between 2 types w/ a Func) except you get an Expression instead just a Func. This Expression is then passed to the Select projection any time AutoMapper finds the source/destination types for a custom projection.
The rest of your config is:
Mapper.CreateMap<DbModel.Kabinetas, Kabinetas>()
.ForMember(n => n.Numeris, m => m.MapFrom(f => f.Numeris ?? ""));
Mapper.CreateMap<DbModel.Specialybe, Specialybe>()
.ForMember(i => i.Istaigos, y => y.Ignore());
Have you tried ValueResolver<TSource, TDestination> ?
A simple example (string id to mongodb objectid):
public class UserIdResolver : ValueResolver<UserViewModel, ObjectId>
{
protected override ObjectId ResolveCore(UserViewModel source)
{
ObjectId objectId = new ObjectId();
if (!string.IsNullOrEmpty(source.Id))
{
objectId = new ObjectId(source.Id);
}
return objectId;
}
}
And the mapping goes like this:
Mapper.CreateMap<UserViewModel, UserEntity>()
.ForMember(dest => dest.Id, src => src.ResolveUsing<UserIdResolver>());
We are relatively new to ReactiveUI so this may explain why we are having some issues with getting a view model working.
In our view model we have a ReactiveList of a class , for which there is a 'selected' in the class.
In the view model we want to have a 'AnySelected' property such that if there is at least 1 item in the list marked as selected then AnySelected is true.
We are having difficulty in getting this work.
As a small test application, with just strings, we have tried this, but messages around changes occurring don't appear.
public class TestRx : ReactiveObject
{
private ReactiveList<string> mySelectedItems;
public ReactiveList<string> MySelectedItems
{
get { return mySelectedItems; }
set { this.RaiseAndSetIfChanged(ref mySelectedItems, value); }
}
public TestRx()
{
var firstList = new ReactiveList<string>();
var t = this.WhenAnyValue(x => x.MySelectedItems);
var t1 = t.Select(x => x ?? new ReactiveList<string>());
var changed = t1.Select(x => x.Changed.Select(_ => Unit.Default));
var itemChanged = t1.Select(x => x.ItemChanged.Select(_ => Unit.Default));
var countChanged = t1.Select(x => x.CountChanged.Select(_ => Unit.Default));
t.Subscribe(x => Debug.WriteLine("T HAS CHANGED {0}", x == firstList));
t1.Subscribe(z => Debug.WriteLine("T1 Changed {0}", z == firstList));
changed.Subscribe(x => Debug.WriteLine("Changed :"));
itemChanged.Subscribe(x => Debug.WriteLine("Item Changed :"));
var replacementList = new ReactiveList<SelItem>(new[] {
new SelItem() { Selected = false }
});
Debug.WriteLine("***********************Assign 1st list");
MySelectedItems = firstList;
Thread.Sleep(100);
Debug.WriteLine("***********************Adding item 2 list");
MySelectedItems.Add("a new string");
// we don't get any debug messages as a result of the above
Thread.Sleep(100);
Debug.WriteLine("***********************Assign null");
MySelectedItems = null;
Thread.Sleep(100);
}
}
What are we doing wrong ?
This is a common pattern, but it's a bit tricky to implement, because you have to handle all of the following scenarios:
The list is set
The list items change
The "Selected" property on any items change. Keep in mind, the items you want to watch, change because of #1 or #2.
How do I do it?
Here's one way to do it. It's complicated, and that hints at a place where future versions of RxUI could make things Better, but here's what you can do for now.
IObservable<bool> WhenAnyAreTrue(IEnumerable<ViewModel> currentElements)
{
// NB: 'Unit' here means, we don't care about the actual value, just
// that something changed
var notifyWhenAnySelectedItemChanges = currentElements
.Select(x => x.WhenAny(y => y.Selected, _ => Unit.Default).Skip(1))
.Merge();
return notifyWhenAnySelectedItemChanges
.StartWith(Unit.Default)
.Select(_ => currentElements.Any(x => x.Selected));
}
// Any time MySelectedItems change or when the items in it change,
// create a new WhenAnyAreTrue and switch to it
this.WhenAnyObservable(x => x.MySelectedItems.ItemsChanged)
.Select(_ => WhenAnyAreTrue(MySelectedItems))
.Switch()
.ToProperty(this, x => x.AnySelected, out anySelected);
What I am doing is this:
Item.PropertyChanged += (sender, args) =>
{
if(sender is IInterface)
DoSomethingWith(((IInterface)sender).PropertyFromInterface);
}
how would I go about implementing such a stream in RxUI?
I tried this:
this.WhenAny(x => (x.Item as IInterface).PropertyFromInterface, x.GetValue())
.Subscribe(DoSomethingWith);
but it seems that is not possible to do.
Would I have to make a property like this? ->
private IInterface ItemAsInterface { get { return Item as IInterface; } }
I made a workaround for now like this:
this.WhenAny(x => x.Item, x => x.GetValue()).OfType<IInterface>()
.Select(x => x.PropertyFromInterface).DistinctUntilChanged()
.Subscribe(DoSomethingWith);
but what I actually want is getting the propertychanged updates for "PropertyFromInterface" while Item is of IInterface.
How about:
this.WhenAny(x => x.Item, x => x.Value as IInterface)
.Where(x => x != null)
.Subscribe(DoSomethingWith);
Update: Ok, I vaguely understand what you want to do now - here's how I would do it:
public ViewModelBase()
{
// Once the object is set up, initialize it if it's an IInterface
RxApp.MainThreadScheduler.Schedule(() => {
var someInterface = this as IInterface;
if (someInterface == null) return;
DoSomethingWith(someInterface.PropertyFromInterface);
});
}
If you really want to initialize it via PropertyChanged:
this.Changed
.Select(x => x.Sender as IInterface)
.Where(x => x != null)
.Take(1) // Unsubs automatically once we've done a thing
.Subscribe(x => DoSomethingWith(x.PropertyFromInterface));
Checked back with my old questions, I was looking for something like this solution:
this.WhenAny(x => x.Item, x => x.GetValue())
.OfType<IInterface>()
.Select(x => x.WhenAny(y => y.PropertyFromInterface, y => y.Value)
.Switch()
.Subscribe(DoSomethingWith);
The missing link for me was the .Switch method.
Additionally, I wanted the observable to not do anything if the property is NOT of the needed type:
this.WhenAny(x => x.Item, x => x.Value as IInterface)
.Select(x => x == null ?
Observable.Empty :
x.WhenAny(y => y.PropertyFromInterface, y => y.Value)
.Switch()
.Subscribe(DoSomethingWith);
(e.g. When I set this.Item to an instance of IInterface, I wanted DoSomethingWith to listen to changes to that instance's PropertyFromInterface, and when this.Item gets set to something different, the observable should not continue to fire until this.Item is an instance of IInterface again.)