I read somewhere that it was best practice to use structs when passing around model data using Swift.
I have been doing so but I have been wondering whether there is anything that I can do in regards to the creation of large (and growing) user data objects like this:
struct UserAccount {
var id: String?
let authId: String
let emailAddress: String
let mobilePhoneNumber: String
let firstName: String
let lastName: String
let countryCode: String
let homepageUrl: String
let tagline: String
let pictureUrl: String
let accountState: AccountState = .NoAccount
// ...
}
This is more or less what I use when I create a user account, but later on it feels cumbersome and wrong to have to instantiate gigantic objects in code. I am parsing JSON responses using json-swift but then having to instantiate the models separately, like so:
let id = jsonData["id"].string!
let authId = jsonData["authId"].string!
let emailAddress = jsonData["emailAddress"].string!
let mobilePhoneNumber = jsonData["mobilePhoneNumber"].string!
let firstName = jsonData["firstName"].string!
let lastName = jsonData["lastName"].string!
let countryCode = jsonData["countryCode"].string!
let homepageUrl = jsonData["homepageUrl"].string!
let tagline = jsonData["tagline"].string!
let pictureUrl = jsonData["pictureUrl"].string!
let accountState = convertAccountStateStringToEnum(jsonData["accountState"].string!)
let userAccount = UserAccount(
id: id,
authId: authId,
emailAddress: emailAddress,
mobilePhoneNumber: mobilePhoneNumber,
firstName: firstName,
lastName: lastName,
countryCode: countryCode,
homePageUrl: homepageUrl,
tagline: tagline,
pictureUrl: pictureUrl,
accountState: accountState
)
It might seem absurd that above I've instantiated the variables before I instantiate the struct, but the reason I did so is that when the IDE gives me type coercion errors from within a struct it is very difficult to understand what is wrong, and so this allows me to troubleshoot it quicker when I am making model changes. Any thoughts around this?
My Question:
Later on that user object is likely to contain a lot more data on the server side and instantiating use models with 50+ lines seems like a bad idea, therefore:
Are there solutions to create structs in some simpler way? Does the pattern have a name?
Should I be creating User models that are related to specific tasks? For example, a UserAccount model to GET or PUT a profile might be different from the one used to authenticate, get the user settings or list the most popular accounts on my service.
Do people just leave it as it is and define mappers so that there is no redundancy? If so - what's a good example of this?
Thanks.
When faced with this, I would build another initializer for the model that takes the JSON data:
struct UserAccount {
// ...
init(jsValue: JSValue) {
id = jsonData["id"].string!
authId = jsonData["authId"].string!
emailAddress = jsonData["emailAddress"].string!
mobilePhoneNumber = jsonData["mobilePhoneNumber"].string!
firstName = jsonData["firstName"].string!
lastName = jsonData["lastName"].string!
countryCode = jsonData["countryCode"].string!
homepageUrl = jsonData["homepageUrl"].string!
tagline = jsonData["tagline"].string!
pictureUrl = jsonData["pictureUrl"].string!
accountState = convertAccountStateStringToEnum(jsonData["accountState"].string!)
}
}
Then you can simply create new UserAccount instances from your JSON data:
let userAccount = UserAccount(jsValue: jsonData)
A few thoughts:
Can you share the reference that suggests its best practice to use structs rather than classes when passing around model data? I would have thought that passing around structs (especially big ones) by value would be less efficient than passing around class instances by reference.
See Choosing between classes and structures in The Swift Programming Language: Classes and Structures which suggests you want to use structures when:
The structure’s primary purpose is to encapsulate a few relatively simple data values.
It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
The structure does not need to inherit properties or behavior from another existing type.
Your user object does not seem to match this criteria. I would have thought the class approach is more logical.
BTW, if using classes, you can also simplify the code to instantiate an object if the class is KVO compliant. For example, you can iterate through an array of key names, grabbing the value associated with each key name from the JSON and then using setValue:forKey: to set the object's property for that particular key.
For more information about KVO-compliance see the Key-Value Observing Programming Guide: KVO Compliance. For more information about how to make Swift object KVO-compliant, see Key-Value Observing section of Using Swift with Cocoa and Objective-C: Adopting Cocoa Design Patterns.
In terms of separate user models for different tasks, that doesn't makes sense for me. You might have different objects for different functional purposes (e.g. accounts/authentication objects) which might reference the user objects, but it doesn't seem to make sense to have different types of user classes/structures.
Related
Is there a way to restrict the "columns" returned from a Realm Xamarin LINQ query?
For example, if I have a Customer RealmObject and I want a list of all customer names, do I have to query All<Customer> and then enumerate the results to build the names list? That seems cumbersome and inefficient. I am not seeing anything in the docs. Am I missing something obvious here? Thanks!
You have to remember that Realm is an object based store. In a RDBMS like Sqlite, restricting the return results to a sub-set of "columns" of an "record" makes sense, but in an object store, you would be removing attributes from the original class and thus creating a new dynamic class to then instantiate these new classes as objects.
Thus is you want just a List of strings representing the customer names you can do this:
List<string> names = theRealm.All<Customer>().ToList().Select(customer => customer.Name).ToList();
Note: That you take the Realm.All<> results to a List first and then using a Linq Select "filter" just the property that you want. Using a .Select directly on a RealmResults is not currently supported (v0.80.0).
If you need to return a complex type that is a subset of attributes from the original RealObject, assuming you have a matching POCO, you can use:
var custNames = theRealm.All<Customer>().ToList().Select((Customer c) => new Name() { firstName = c.firstName, lastName = c.lastName } );
Remember, once you convert a RealmResult to a static list of POCOs you do lose the liveliness of using RealmObjects.
Personally I avoid doing this whenever possible as Realm is so fast that using a RealmResult and thus the RealObjects directly is more efficient on processing time and memory overhead then converting those to POCOs everytime you need to new list...
I have a stored proc that returns a list of users (rows in User table).
var admins = db.aspnet_UsersInRoles_GetUsersInRoles('/', "Admin");
LINQ generated aspnet_User classes for me, so can I somehow map the result to a List of aspnet_User type? Something like:
List<aspnet_User> admins = db.aspnet_UsersInRoles_GetUsersInRoles('/', "Admin");
Here is a capture of what is returned.
It's entirely possible that you just need:
List<aspnet_User> admins = db.aspnet_UsersInRoles_GetUsersInRoles('/', "Admin")
.ToList();
But it's hard to know without seeing what type the method call returns.
Perhaps this should be a comment but it is way too long...
Well, you do not really want the internal class <aspnet_User> you should want a MembershipUser.
So how about not using the stored procedure that comes with the membership provider but really use the Membership provider itsself.
There is a beautiful class: Roles in System.Web.Security
And it gives you this:
public static string[] GetUsersInRole(string roleName)
From here, a foreach to get the MembershipUser(s) in a list is not that complicated.
By default a stored procedure will return a type that it determines based on the output columns with Result tacked on to the end. It doesn't associate it with types you have already determined. To change this, you can either change the Return Type in the property window to the type you have already defined in your model, or when dragging the stored proc into your model, drop it directly on the type that you want the stored proc to be mapped into.
You don't get the opportunity to change the column mappings for stored procs however, so make sure the shape that the stored proc generates is the same as your target object structures.
It's an old post and I was working on it today and I get the same issue,
I think you are requesting asp membership ?
You can not convert this stored procedure to aspnet_User because it returns aspnet_UsersInRoles_GetUsersInRolesResult type.
but from this aspnet_UsersInRoles_GetUsersInRolesResult you can get userName, then request the aspnet_User table:
String app = "your application name";
String role = "your role name";
ArrayList userInRoleList = new ArrayList();
//Get the role ID
ASPNETDBDataContext aspDB = new ASPNETDBDataContext();
var userInRole = aspDB.aspnet_UsersInRoles_GetUsersInRoles(app, role);
foreach (aspnet_UsersInRoles_GetUsersInRolesResult users in userInRole)
{
userInRoleList.Add(users.UserName);
}
I'm working on a custom linq extension for nHibernate by extending the BaseHqlGeneratorForMethod. The technique is documented here:
http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html
I've had success with implementing these for various types of operations, but I must say - converting a simple linq expression to its full expression tree is not easy! I'm stuck on one now.
For this example, I have three entities. Employee, Group, and EmployeeGroup. The EmployeeGroup class sets up a many-to-many relationship between Employee and Group. I must specifically create the intermediate class because there are additional properties to track like specific permissions each employee has in each group. So there are two one-to-many relationships, rather than an nHibernate many-to-many relationship.
Now say I want to get all groups that contain a specific employee. I can write this query:
var groups = session.Query<Group>()
.Where(g => g.EmployeeGroups.Any(eg => eg.Employee == employee));
This works fine, but it's a lot to type. I'd much rather be able to do this:
var groups = session.Query<Group>().Where(g => g.HasEmployee(employee));
I start by creating an extension method like so:
public static bool HasEmployee(this Group group, Employee employee)
{
return group.EmployeeGroups.Any(eg => eg.Employee == employee);
}
This works when querying a local list of groups, but not against the nHibernate session. For that, I have to also create a linq extension and register it. Just like in the article (linked above), I create a GroupHasEmployeeGenerator class that extends BaseHqlGeneratorForMethod. I set its .SupportedMethods property to reference my HasEmployee extension method.
Where I get lost is in the override to BuildHql. The expression to build gets complicated pretty fast. I figure since I'm replacing the .Any clause - a good place to start is with the source for the built-in AnyHqlGenerator class. But that doesn't take into account that the source is a property of the original element, and it also doesn't take into account that I don't have a lambda expression to represent the where clause. I need to build these parts manually.
There's no point in posting my attempts so far, as they've all be quite far from anything that would work.
Will someone please help me convert this simple expression into the approprate set of methods for the BuildHql method override?
If there is any better documentation out there for this, please let me know. Thanks.
I know this question is a year old, but I ran into a very similar issue when implementing BaseHqlGeneratorForMethod today.
The input to BuildHql contains a collection of System.Linq.Expressions.Expression arguments that are passed to your extension method. Using these arguments, you can build an expression tree that represents the implementation of your extension method. If the resulting expression is something NHibernate.Linq supports, then you can transform that expression to a subtree of Hql using the provided IHqlExpressionVisitor.
In your example:
public static bool HasEmployee(this Group group, Employee employee)
{
return group.EmployeeGroups.Any(eg => eg.Employee == employee);
}
This would become something similar to this:
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
var AnyMethod = EnumerableHelper.GetMethod("Any", new[] {typeof(IEnumerable<EmployeeGroup>), typeof(Func<EmployeeGroup, bool>)}, new[] {typeof(EmployeeGroup)});
var EmployeeGroupsProperty = ReflectionHelper.GetProperty<Group>(g => g.EmployeeGroups);
var EmployeeProperty = ReflectionHelper.GetProperty<EmployeeGroup>(eg => eg.Employee);
var EmployeeGroupParameter = Expression.Parameter(typeof(EmployeeGroup));
var EmployeeGroupPredicate = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(EmployeeGroupParameter, EmployeeProperty), arguments[1]), EmployeeGroupParameter);
var CallExpression = Expression.Call(AnyMethod, Expression.MakeMemberAccess(arguments[0], EmployeeGroupsProperty), EmployeeGroupPredicate);
return visitor.Visit(CallExpression);
}
I can't really test this specific example, but the same approach worked for me when providing support for my own extension method.
I'm using a function :
fu_has_permissions(udt_person('johny','superman'),'fly_away')
udt_person is a user defined type :
create or replace TYPE udt_person AS OBJECT
(name VARCHAR2(3),
id VARCHAR2(18));
I want to use bind variables whan calling this function, but i'm not really sure what am i doing wrong ... Here's the code :
......
OracleParameter udtPersParam = new OracleParameter();
udtPersParam.ParameterName = ":pUdtPers";
udtPersParam.UdtTypeName = "UDT_PERS";
string[] paramValues = { name, id };
udtPersParam.Value = paramValues;
OracleParameter pAction = new OracleParameter(":pAction", OracleDbType.Varchar2, 255);
pAction.Value = action;
parameters.Add(udtPartParam);
parameters.Add(pAction);
try
{
_loginOdr = DBFacade.ExecuteSelectQuery("select fu_has_permissions(:pUdtPart, :pAction) from dual", parameters);
}
Thanks!
the udt type must be a class that implements
IOracleCustomType
and/or IOracleCustomTypeFactory, IOracleArrayTypeFactory
unfortuntately you cannot just create a string array and pass it in
look in the odp.net samples that come with the odp installation
%ora_home%\client_1\odp.net\samples\4\UDT
also check out these links for samples and walkthroughs
http://developergeeks.com/article/35/working-with-user-defined-type-oracle-udt-and-custom-type-using-odp-net-11g
http://www.codeproject.com/KB/database/ORACLE_UDT.aspx
and
http://st-curriculum.oracle.com/obe/db/hol08/dotnet/udt/udt_otn.htm
Don't know anything about ODP.Net really, but the error suggests that it doesn't like you trying to use a string array as the value for an Oracle parameter. Which doesn't sound unreasonable.
A quick google of 'odp.net object varchar2' gave this OTN forum post as the first result; it includes an example of using an object about half-way down, including converting to and from Oracle object types.
if I were you I'd have a look at the ODP add-in to Visual Studio. With this you can connect to your database, select a UDT on the database, and "Generate Custom Class" to get a .net class you can use.
Look inside the class and you'll see what Harrison means. Pay particular attention to the OracleObjectMappingAttributes on top of the properties, and the overrides of To/FromCustomObject.
When you construct your OracleCommand, the OracleParameter.Value needs to be a class of this type.
That should get you started at a high level. A word of warning, though. The code generated by ODP is ugly to say the least - we're on the point of ditching all ODP-generated classes in our own scenario. But you'll need to understand what things like IOracleCustomType, IOracleCustomTypeFactory, IOracleArrayTypeFactory, INullable are before you'll be in a position to do this.
Incidentally since your specific question surrounds arrays, you might want to look at Oracle NTYPEs here, rather than TYPEs.
I would like to populate a Treeview.
Here is what I have in DB :
table : Box
BoxID
BoxName
table Book :
BookID
BookName
BoxID (fk Box.BoxID)
table Chapter:
ChapterID
ChapterName
BookID (fk Book.BookID)
As you may know a treeview is made up of treenode object.
A treenode object have a text property and a tag property.
The "text" property is the text that it's display on the screen for this node and the "tag" is an "hidden" value (usually uses to identify a node)
So in my case; the fields ending with ID will be used in the "tag" property and the fields ending with Name will be used in the "text" property
example :
so for a book; I will use the BookID field for the "tag" property and BookName field for the "text" property
note : I use a dbml so I have a Book object, Box object and Chapter object and I use linq to get them from the db.
So my question is; what is the best practice to build this tree?
I have a solution but it's really ugly because it looks like I'm duplicating the code.
The problem is that the values I need to extract for the text and tag properties are identified by differents fields name in the db
So for the book level, I need to get the BookID field to populate the tag property of my node; for the box level, I need to get the BoxID field to populate the tag property , ....
How can I make a kind of generic way to do it ?
I hope I made myself clear enough, don't hesitate to ask me questions :)
Thx in advance
Here is what I have for the moment
I get the list of box with a linq (dbml) request.
List<Box> MyListofBox = getMyListofBox();
Treenode tnBox = null;
Treenode tnBook =null;
foreach(Box b in MyListofBox )
{
tnBox = new TreeNode();
tnBox.tag = b.BoxID;
tnBox.text = b.BoxName;
List<Book> MyListofBook = getMyListofBookByBoxID(b.BoxID)
foreach(Book boo in MyListofBook )
{
tnBook = new TreeNode();
tnBook.tag = boo.BookID;
tnBook.text = boo.BookName;
tnBox.nodes.add(tnBook);
}
mytreeview.nodes.add(tnBox);
}
but of course I don't like this solution...
do you have a better way ?
I would extract the you need from the database in the form of a struct, possibly via the anonnoumous type that has been added to C# together with linq. Then I would populate insert this data into the place in the tree.
From what I get, you are trying to get each property separately, which will not work so well, because then you will have to make a call to the database for each separate property, which is very wasteful.
Addition based on what you have added
I do not believe the code can be more compact - the names you call are similar, but not the same and the way you do it was what I was trying to explain earlier.
You could
Define an key/value interface that both Box and Book implement
Define a delegate that returns a TreeNode and create delegate methods that accept Box and Book
However, I think the code is fine as written. Sometimes you just have to code it and there's little point in further abstracting or optimizing it.
The only issue I see in the code is that you're making a database call in a loop. Whether or not that's a problem depends on the application.