Get Access property of a CodeElement - visual-studio

I'm writing an Add-in for VS 2010. Can't find answer for a question - How can i get the Access property of a CodeElement if it has that one.
I was trying reflection, but no results.
Ex. CodeElement is a class method
public void GetAccess (CodeElement codeElement)
{
object code = codeElement;
Type t = code.GetType();
t.GetProperty("Access") = vsCMAccess.vsCMAccessPublic;
}
But it doesnt work..
Help, please!

Access is only available on some types of CodeElements, so you'll need to check for the type of CodeElement you have, cast to the specific type and then retrieve the property.
Example:
if (codeElement.Kind == vsCMElementFunction)
{
return ((CodeFunction)codeElement).Access;
}
else if (codeElement.Kind == vsCMElementProperty)
{
return ((CodeProperty)codeElement).Access;
}

Related

Debugger shows not existing properties of an object

I am using Svg .Net lib. Here is my method code
public void X()
{
Svg.SvgDocument svgDocument = SvgDocument.Open(Path);
foreach (var child in svgDocument.Children)
{
foreach (var step in child.Children)
{
if (step.ID.StartsWith("node"))
{
var el = step.Children[2];
var id = el.Content;
}
}
}
}
And here is what I can see in a debugger:
My question is how I can see Bounds property if object does not have it?
Thanks!
The debugger always shows the properties of the actual (dynamic) instance of the object, not the static type of the variable you're referring to. It tries to give you as much information about the object as possible. If you check the third column in the watch window, it tells you the static type of the variable (SvgElement) and its dynamic type (SvgText) in braces. Expanding a variable shows the properties and fields of the dynamic type.

Get StringLength attribute from CodeProperty?

I have created a set of T4 templates to generate the unit classes for a DAL. An issue I have is with providing a string of the correct length based on "StringLength" attribute on the properties of the entities.
I tried accessing CodeProperty.Attributes, but it says there are zero attributes where I know that to be incorrect.
Any help would be greatly appreciated!
Just in case someone else stumbles upon this......
I was unable to utilize CodeProperty to obtain the attribute. Instead I use the following given I already have a CodeClass and CodeProperty to use in my search:
private int GetStringLength(CodeProperty codeProperty, CodeClass codeClass)
{
var type = Type.GetType(codeClass.Name); //you may need to use assembly qualified name
var props = type.GetProperties();
if (props != null && props.Any(p => p.Name.Equals(codeProperty.Name)))
{
var matchingProperty = props.First(p => p.Name.Equals(codeProperty.Name);
var strLenAttr = (StringLengthAttribute) matchingPropery.GetCustomAttributes(typeof(StringLengthAttribute), true).FirstOrDefault();
if (strLenAttr == null) return 0;
return strLenAttr.MaximumLength;
}
return 0;
}

IEqualityComparer exception

I am using Entity Framework 4.0 and trying to use the "Contains" function of one the object sets in my context object. to do so i coded a Comparer class:
public class RatingInfoComparer : IEqualityComparer<RatingInfo>
{
public bool Equals(RatingInfo x, RatingInfo y)
{
var a = new {x.PlugInID,x.RatingInfoUserIP};
var b = new {y.PlugInID,y.RatingInfoUserIP};
if(a.PlugInID == b.PlugInID && a.RatingInfoUserIP.Equals(b.RatingInfoUserIP))
return true;
else
return false;
}
public int GetHashCode(RatingInfo obj)
{
var a = new { obj.PlugInID, obj.RatingInfoUserIP };
if (Object.ReferenceEquals(obj, null))
return 0;
return a.GetHashCode();
}
}
when i try to use the comparer with this code:
public void SaveRatingInfo2(int plugInId, string userInfo)
{
RatingInfo ri = new RatingInfo()
{
PlugInID = plugInId,
RatingInfoUser = userInfo,
RatingInfoUserIP = "192.168.1.100"
};
//This is where i get the execption
if (!context.RatingInfoes.Contains<RatingInfo>(ri, new RatingInfoComparer()))
{
//my Entity Framework context object
context.RatingInfoes.AddObject(ri);
context.SaveChanges();
}
}
i get an execption:
"LINQ to Entities does not recognize the method 'Boolean Contains[RatingInfo](System.Linq.IQueryable1[OlafCMSLibrary.Models.RatingInfo], OlafCMSLibrary.Models.RatingInfo,
System.Collections.Generic.IEqualityComparer1[OlafCMSLibrary.Models.RatingInfo])' method, and his method cannot be translated into a store expression."
Since i am not proficient with linQ and Entity Framework i might be making a mistake with my use of the "var" either in the "GetHashCode" function or in general.
If my mistake is clear to you do tell me :) it does not stop my project! but it is essential for me to understand why a simple comparer doesnt work.
Thanks
Aaron
LINQ to Entities works by converting an expression tree into queries against an object model through the IQueryable interface. This means than you can only put things into the expression tree which LINQ to Entities understands.
It doesn't understand the Contains method you are using, so it throws the exception you see. Here is a list of methods which it understands.
Under the Set Methods section header, it lists Contains using an item as supported, but it lists Contains with an IEqualityComparer as not supported. This is presumably because it would have to be able to work out how to convert your IEqualityComparer into a query against the object model, which would be difficult. You might be able to do what you want using multiple Where clauses, see which ones are supported further up the document.

How to access data into IQueryable?

I have IQueryable object and I need to take the data inside the IQueryable to put it into Textboxs controls. Is this possible?
I try something like:
public void setdata (IQueryable mydata)
{
textbox1.text = mydata.????
}
Update:
I'm doing this:
public IQueryable getData(String tableName, Hashtable myparams)
{
decimal id = 0;
if (myparams.ContainsKey("id") == true)
id = (decimal)myparams["id"];
Type myType= Type.GetType("ORM_Linq." + tableName + ", ORM_Linq");
return this.GetTable(tableName , "select * from Articu where id_tipo_p = '" + id + "'");
}
public IQueryable<T> GetTable<T>(System.Linq.Expressions.Expression<Func<T, bool>> predicate) where T : class
{
return _datacontext.GetTable<T>().Where(predicate);
}
This returns a {System.Data.Linq.SqlClient.SqlProvider+OneTimeEnumerable1[ORM_Linq.Articu]}`
I don't see any method like you tell me. I see Cast<>, Expression, ToString...
EDIT: Updated based on additional info from your other posts...
Your getData method is returning IQueryable instead of a strongly typed result, which is why you end up casting it. Try changing it to:
public IQueryable<ORM_Linq.Articu> getData(...)
Are you trying to query for "Articu" from different tables?
With the above change in place, your code can be rewritten as follows:
ORM_Linq.Articu result = mydata.SingleOrDefault();
if (result != null)
{
TextBoxCode.Text = result.id.ToString();
TextBoxName.Text = result.descrip;
}
If you have a single result use SingleOrDefault which will return a default value if no results are returned:
var result = mydata.SingleOrDefault();
if (result != null)
{
textbox1.text = result.ProductName; // use the column name
}
else
{
// do something
}
If you have multiple results then loop over them:
foreach (var item in mydata)
{
string name = item.ProductName;
int id = item.ProductId;
// etc..
}
First, you should be using a strongly-typed version of IQueryable. Say that your objects are of type MyObject and that MyObject has a property called Name of type string. Then, first change the parameter mydata to be of type IQueryable<MyObject>:
public void setdata (IQueryable<MyObject> mydata)
Then we can write a body like so to actually get some data out of. Let's say that we just want the first result from the query:
public void setdata (IQueryable<MyObject> mydata) {
MyObject first = mydata.FirstOrDefault();
if(first != null) {
textbox1.Text = first.Name;
}
}
Or, if you want to concatenate all the names:
public void setdata(IQueryable<MyObject> mydata) {
string text = String.Join(", ", mydata.Select(x => x.Name).ToArray());
textbo1.Text = text;
}
Well, as the name suggests, an object implementing IQueryable is... Queryable! You'll need to write a linq query to get at the internal details of your IQueryable object. In your linq query you'll be able to pull out its data and assign bits of it where ever you'd like - like your text box.
Here's a great starting place for learning Linq.
I think you find the same mental struggle when coming from FoxPro and from DataSet. Really nice, powerful string-based capabilities(sql for query, access to tables and columns name) in these worlds are not available, but replaced with a compiled, strongly-typed set of capabilities.
This is very nice if you are statically defining the UI for search and results display against a data source known at compile time. Not so nice if you are trying to build a system which attaches to existing data sources known only at runtime and defined by configuration data.
If you expect only one value just call FirstOrDefault() method.
public void setdata (IQueryable mydata)
{
textbox1.text = mydata.FirstOrDefault().PropertyName;
}

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