How do I query Realm database based on current user ID? - swift2

I have a Realm database which holds records for different users with distinct userID's.
I also have a UITableViewController which displays the results of a Realm query. I would like the query to return only the Passages for the current user.
class PassageListController: UITableViewController {
var currentUserID: Int = NSUserDefaults.standardUserDefaults().objectForKey("currentUserID") as! Int
lazy var dataArray: Results<Passage> = { return try! Realm().objects(Passage).filter("userID == \(currentUserID)")}
The problem is that I'm getting the following error message:
Instance member 'currentUserID' cannot be used on type 'PassageListController'
This is despite trying to lazily load the Realm query. What is the best practice method to solve this problem?
Anticipating some solutions:
I can't load the query in viewDidAppear() as there is no way to define an empty Realm Result and it needs to be accessible throughout the controller.
I could set the currentUserID as a global variable but that violates my principles.

It looks like it's having some trouble working out the computed value of currentUserID before even getting to the Realm query.
Looking around on SO, it looks like this sort of issue can be solved by changing the definition of currentUserID to a read-only accessor:
var currentUserId: Int {
get {
return NSUserDefaults.standardUserDefaults().objectForKey("currentUserID") as! Int
}
}
I hope that helped!

TiM's answer clued me in to the right approach:
class PassageListController: UITableViewController {
var currentUserID: Int = NSUserDefaults.standardUserDefaults().objectForKey("currentUserID") as! Int
var dataArray: Results<Passage> {
get {
return try! Realm().objects(Passage).filter("userID == \(currentUserID)")
}
}
The project builds now but I'm not sure whether this is the best approach with Realm because
now the query will potentially be run every time dataArray is accessed, and
I'm not sure whether Realm's notifications will work.

Related

Better way to handle this code

I am working on a MVC3 application with nhibernate and SQL server. Have written a normal method which is re-usable. Please find the below code and let me know a better way to handle it. I have observed to execute this piece of code it is taking a long time.
private void GetParentCompany(IEnumerable<Company> companiesList)
{
foreach (var company in companiesList)
{
long? dunsUltimateParent = company.DUNSUltimateParent;
Company ultimateParent = _companyService.GetCompanyByDUNS(Convert.ToInt64(dunsUltimateParent));
if (ultimateParent != null)
{
company.UltimateParentName = ultimateParent.CompanyName;
company.UltimateCompanyId = ultimateParent.CompanyId;
company.UltimateParentDuns = ultimateParent.DUNS;
}
}
}
Adding an index to your company.DUNS column might help. However consider to introduce a many-to-one relationship from company to (parent) company.
Place a UltimateParent property with type company in the company class. The fields UltimateParentName and UltimateParentDuns would then be redundant and you could simply get company.UltimateParent.Name for example. The mapping of UltimateParent can be done using 'References' in fluent-nhibernate.
References(x => x.UltimateParent);

LINQ: use anonymous type

I'm sure that this is basic for someone that knows the answer. But I'm stuck. I've tried to look up the answer to no avail. How do I reference the fbRegistered value later in the code?
using (kvEntities ent = new kvEntities())
{
var user = from u in ent.kvUsers
where u.fbID == id
select new { u.fbID, u.fbRegistered};
if (user.fbRegistered) // < ???
{
// so how do I reference fbRegistered just above?
// this gives me an error.
}
}
Thanks!
The user contains collection. Use First or Single methods:
if (user.First().fbRegistered) ...

Users restrictions for associated data in ASP Membership

I have a site I'm porting to MVC to clean up the code and simplify things. I use the asp membership and profile providers, but I'm wondering if I'm doing this correctly for my situtation. I'm pretty new to MVC, so I wan to get this right in the early stages.
Users are individuals and they are part of larger "institutions" that they either set up or pick at registration. In this case, the institution is a winery. I want the users to be able to view all wines from every winery, but only edit ones that belong to them.
What's the best way to do this? Right now I render the link to the edit field in my index view based on their instution ID and the producer ID. I feel like a data annotation might work better here, but I don't exactly how to implement that for a group of wines. Do I need multiple providers? I use roles to limit the editing, but right now an editor role could manually enter the path of another wine to edit it when that wine doesn't belong to them.
Any pointers here would be awesome. I know I can do it in the controller methods, but I'm looking for the 'right' way to do it. Thanks.
I'm running into the same issue at work right now, and the best proposed solution we have right now is implementing an "ownership" table. You won't be able to solve this using roles.
So basically you have an owner ID, owned object's ID, and the type of objects ID all held together. Lets take an edit request for example. We know that you can only edit the data person X owns, so we have a stored procedure that if a key combination exists in our ownership table where person.ID = owner ID, and item.ID = object ID, and item.TypeID = objectTypeID. If it exists, it goes along performing its edits, otherwise it returns an error.
You can use this scheme to return ownership lists, user validation, and a host of other issues you may come across. You probably won't need the ObjectTypeID if you only have one type's ownership being tracked. Hope this helps!
I figured this out by applying a custom AuthorizeAttribute to the edit, delete, and create actions.
Here is what I ended up doing:
public class ProducerEditAttribute : AuthorizeAttribute
{
private vfContext db = new vfContext();
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
bool bAdmin = filterContext.HttpContext.User.IsInRole("admin");
bool bProdEdit = filterContext.HttpContext.User.IsInRole("producereditor");
bool bProd = filterContext.HttpContext.User.IsInRole("producer");
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (bAdmin)
{
//authorized
}
if (bProdEdit || bProd)
{
//check for current wine belonging to the producer.
Producer currentProd = db.Producers.Find(Profile.GetProfile(filterContext.HttpContext.User.Identity.Name).InstitutionID);
Wine currentWine;
object WineID;
if (filterContext.RouteData.Values.TryGetValue("id", out WineID))
{
currentWine = db.Wines.Find(int.Parse(WineID.ToString()));
if (currentProd.Wines.Contains(currentWine) && bProdEdit)
{
//authorized
}
else if (bProd)
{
var result = new ViewResult();
result.ViewName = "Login.cshtml"; //this can be a property you don't have to hard code it
result.MasterName = "_Layout.cshtml"; //this can also be a property
result.ViewBag.Message = "You do not have permission for add/edit/delete funciontionality. Please request.";
filterContext.Result = result;
}
else
{
var result = new ViewResult();
result.ViewName = "Login.cshtml";
result.MasterName = "_Layout.cshtml";
filterContext.Result = result;
}
}
}
else
{
var result = new ViewResult();
result.ViewName = "Login.cshtml";
result.MasterName = "_Layout.cshtml";
}
}
}
}

Entity Framework 4 - List<T> Order By based on T's children's property

I have the following code -
public void LoadAllContacts()
{
var db = new ContextDB();
var contacts = db.LocalContacts.ToList();
grdItems.DataSource = contacts.OrderBy(x => x.Areas.OrderBy(y => y.Name));
grdItems.DataBind();
}
I'm trying to sort the list of the contacts according to the area name that is contained within each contact. When I tried the above, I get "At least one object must implement IComparable.". Is there an easy way instead of writing a custom IComparer?
Thanks!
try this:
public void LoadAllContacts()
{
var db = new ContextDB();
var contacts = db.LocalContacts.ToList();
grdItems.DataSource = contacts.OrderBy(x => x.Areas.OrderBy(y => y.Name).First().Name);
grdItems.DataBind();
}
this will order the contacts by the first area name, after ordering the areas by name.
Hope this helps :)
Edit: fixed error in code. (.First().Name)
I was in a discussion with #AbdouMoumen but in the end I thought I'd provide my own answer :-)
His answer works, but there two performance issues in this code (both in the answer as in the original question).
First, the code loads ALL contacts in the db. This may or may not be a problem, but in general I would recommend NOT to do this. Many modern controls support paging/filtering out of the box, so you'd be better off supplying an not-yet-evaluated IQueryable<T> instead of List<T>. If however you need everything in memory, you should delay the ToList to the last possible moment.
Second, in AbdouMoumen's answer, there is a so-called 'SELECT N+1' problem. Entity Framework will by default use lazy loading to fetch additional properties. I.e. the Areas property will not be fetched from the database until it's accessed. In this case this will happen in the controls 'for loop', while it's ordering the result set by name.
Open up SQL Server Profiler to see what I mean: you will see a SELECT statement for all the contacts, and an additional SELECT statement for each contact that fetches the Areas for that contact.
A much better solution would be the following:
public void LoadAllContacts()
{
using (var db = new ContextDB())
{
// note: no ToList() yet, just defining the query
var contactsQuery = db.LocalContacts
.OrderBy(x => x.Areas
.OrderBy(y => y.Name)
.First().Name);
// fetch all the contacts, correctly ordered in the DB
grdItems.DataSource = contactsQuery.ToList();
grdItems.DataBind();
}
}
Is it one to one relation (Contact->Area)?
if yeah then try the following :
public partial class Contact
{
public string AreaName
{
get
{
if (this.Area != null)
return this.Area.Name;
return string.Empty;
}
}
}
then
grdItems.DataSource = contacts.OrderBy(x => x.AreaName);

How would I get the column names from a Model LINQ?

I am looking to get a list of the column names returned from a Model. Anyone know how this would be done, any help would be greatly appreciated.
Example Code:
var project = db.Projects.Single(p => p.ProjectID.Equals(Id));
This code would return the Projects object, how would I get a list of all the column names in this Model.
Thanks
This would be nice to have as an extension method:
public static class LinqExtensions
{
public static ReadOnlyCollection<MetaDataMember> ColumnNames<TEntity> (this DataContext source)
{
return source.Mapping.MappingSource.GetModel (typeof (DataContext)).GetMetaType (typeof (TEntity)).DataMembers;
}
}
example:
var columnNames = myDataContext.ColumnNames<Orders> ();
Thanks guys, you got me started on the right track. I found my solution with the following code. I can then iterate through the DataMembers and pull out their individual properties such as name, type, etc.
var db = new GMPDataContext();
var columnNames = db.Mapping.MappingSource
.GetModel(typeof(GMPDataContext))
.GetMetaType(typeof(Project))
.DataMembers;
Your Projects wrapper will have a set of properties each with a [Column] attribute. So just use reflection to enumerate the properties with that attribute.
Using Todd Smiths(+1) solution you get all properties (included entity sets, etc).
To filter out all non-column properties this will do the trick:
var columnNames = db.ColumnNames<Orders>().Where(n => n.Member.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false).FirstOrDefault() != null).Select(n => n.Name);
I am sorry, I don't have working experience with LINQ.
This is purely based on looking at MSDN.
DataContext has a Mapping property, which returns an instance of MetaModel.
MetaModel has GetMetaType, which takes a Type. In your case it could be typeof(Project).
GetMetaType returns a MetaType which has the GetDataMember method, which takes a MemberInfo parameter. You will have to use reflection on your Projects object to get the MemberInfo object.
The MetaDataMember instance returned by GetDataMember should have all the things, you need.
I hope I am somewhat in right direction (purely looking at MSDN & traversing)
Your columns should be mapped as properties on your Project model. I'm not sure if you can get the underlying database structure when using LINQ to SQL. The entire point of LINQ to SQL is to abstract the database away.
Here an another way:
public string[] GetColumnNames()
{
var propnames = GetPropertyNames(_context.Users);
return propnames.ToArray();
}
static IEnumerable<string> GetPropertyNames<T>(IEnumerable<T> lst)
{
foreach (var pi in typeof(T).GetProperties())
{
yield return pi.Name;
}
}

Resources